typescripttypestype-inference

Cleanly infer the type of an array value


So technically, I have already figured out an answer to this question, but am looking for a cleaner approach. Similarly, I haven't seen any SO questions or documentation specifically laying out how to do this.

First, an example to then build upon: I know that if I have a typed array, I can infer the type of each value in this way:

// just with types
type Tuple = [item1: number, item2: string];
type Item1Type = Tuple[0]; // type is number
type Item2Type = Tuple[1]; // type is string

// or with `typeof`
const myTuple: Tuple = [1, 'one'];
type InferredItem1Type = typeof myTuple[0]; // type is number
type InferredItem2Type = typeof myTuple[1]; // type is string

If I have a generic like this though and all I have access to is an instance of this type:

// the generic type
type GenericObjectWithList<T> = {
  list: T[];
};

// the instance i have access to
const object: GenericObjectWithList<string> = {
  list: ['one', 'two', 'three'],
};

I want to infer the type of the inner list.

// infer the type of the list
type InferredListType = typeof object['list'][0]; // type is string

As you can see, I've already figured out that I can infer this type similar to the approach in my first example, but I'm wondering, is there a cleaner way to infer this type? I would expect there to be a way to infer the single value type of a list without needing to do [0]. If there isn't a another way to do this, would someone mind explaining why this approach is the only way we'd want this to be the way to infer an array value's type?


Solution

  • Arrays are indexed by a number, which means you can drill into an array with number in order to get the value types from that array.

    ArrayType[number] is typically how you would do this. Indexing a non tuple array by zero is pretty much the same thing, but it hints to the programmer that the indexed value would be different for different numbers, which isn't right.

    type StrArr = string[]
    type ArrVal = StrArr[number] // string
    

    Or from your code:

    type InferredListType = typeof object['list'][number]; // type is string
    

    Playground


    This works with tuples, too.

    type MyTuple = [123, 'asd']
    type TupleVal = MyTuple[number] // 123 | 'asd'
    

    But, of course, you lost the information of the position of each type in that tuple. If you need that, that's where you would use [0], [1], etc, instead.

    Playground