Home > Software engineering >  Mapped type for string doesn't work as expected. Misunderstanding or bug?
Mapped type for string doesn't work as expected. Misunderstanding or bug?

Time:08-02

Why S is string in following code?

type T<X> = {[K in keyof X]: never};
type S = T<string>;

Here is TypeScript playground. https://www.typescriptlang.org/play?#code/C4TwDgpgBAKgPADQHxQLxQN4G0DSUCWAdlANYQgD2AZlAgLoBcUhEAbhAE4C A3AFChIUAMppYcAM7AORAOZIeQA

It becomes the same type (string) even if I replace never by other types.

Adding context, following type works as I expect.

type T<X> = {[K in (keyof X) & string]: never};
type S = T<string>;

CodePudding user response:

Essentially what you are doing is mapping the keys of the type string which are number | typeof Symbol.iterator | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" ... etc. set their types to never. You can do that with a simple Union.

type X = keyof string; // type X = number | typeof Symbol.iterator | "toString" ...

But not with key mapping the way you tried. What you created is a so called What you created is a so called homomorphic mapped type. That means the compiler regognizes you are trying to map the keys of an already existing object type. When that is the case the compiler simple returns a type with the exact same property modifiers as the one on your input type.

In short, when mapping the properties of a primitive type typescript will just return that very primitive type.

This mapped type returns a primitive type, not an object type. Mapped types declared as { [ K in keyof T ]: U } where T is a type parameter are known as homomorphic mapped types, which means that the mapped type is a structure preserving function of T. When type parameter T is instantiated with a primitive type the mapped type evaluates to the same primitive. - TypeScript FAQ Bugs that aren't Bugs

  • Related