danvk / effective-typescript

Effective TypeScript 2nd Edition: 83 Specific Ways to Improve Your TypeScript

Home Page:https://effectivetypescript.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The display of types

utterances-bot opened this issue · comments

The display of types

Effective TypeScript: The display of types

https://effectivetypescript.com/2022/02/25/gentips-4-display/

type Resolve<T> = T extends Function ? T : {[K in keyof T]: T[K]} seems to be able to preserve types like number or "42":

type n = Resolve<number> // number
type s42 = Resolve<"42"> // "42"

How is that even possible? Ahah I mean {[K in keyof "42"]: "42"[K]} is definitely not the same as "42".

It is surprising, isn't it? One clue is that keyof gives the methods defined on the wrapper types for primitives:

type K = keyof number;
//   ^? type K = "toString" | "toFixed" | "toExponential" | ...

But still, I think this must be special-cased in the TypeScript compiler. Especially in the case of a literal type, the result is much more specific than you'd expect. Resolve is magical indeed!

I think I found something: microsoft/TypeScript#12447
{[K in keyof T]: T[K]}is what we now call a homomorphic (previously isomorphic) mapped type, and ahejlsberg said that "when a primitive type is substituted for T in an isomorphic mapped type, we simply produce that primitive type".

So there is a rationale behind this. Nice find @jfet97! It's news to me that "distributing over unions" is a concept that predates conditional types. This behavior was never mentioned in the release notes at the time (2.1 and 2.2).