'Why isn't T[string] a valid object lookup type in TypeScript?

I'm trying to better understand how lookup types work in TypeScript.

I have seen T[number] used as a lookup type that gives a union, like follows:

type Tuple = ['cat', 'dog', 'elephant']
type TupleToUnion = Tuple[number]
// gives union type: 'cat' | 'dog' | 'elephant'

I wanted to use T[string] to do a similar lookup on an object type. The result is not successful:

type Obj = { 'cat': 'cat', 'dog': 'dog', 'elephant': 'elephant' }
type ObjToUnion = Obj[string]
// Type 'Obj' has no matching index signature for type 'string'. (2537)

Why does T[number] work as a lookup type and T[string] does not?



Solution 1:[1]

An array type has an interface similar to this:

interface ArrayLike<T> {
  length: number;
  [key: number]: T;
}

Therefore, ArrayType[number] is correct because the interface specified that all keys will be number type.

For a custom object type, like the one you use in example:

type Obj = {
  'cat': 'cat';
  'dog': 'dog';
  'elephant': 'elephant'
}

While all keys are indeed of string type, only 3 specific string keys are valid: cat, dog, elephant. Therefore, doing Obj[string] is wrong because string represents all string values (like abc, hello, etc), not just the 3 keys.

To use Obj[string], you would need to declare it the way similar to ArrayLike:

type Obj = {
  [key: string]: string;
}

type ObjToUnion = Obj[string]; // ok

To get only the keys from an object, you can use keyof operator:

type Obj = {
  'cat': 'cat';
  'dog': 'dog';
  'elephant': 'elephant'
}

type ObjToUnion = Obj[keyof Obj];

Playground

EDIT

This is called index signature. Its documentation can be found here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1