cmart
cmart

Reputation: 1001

Using Tuples in TypeScript (Type Inference)

Given this slightly artificial example:

['List', 'Of', 'Names']
        .map((name, index) => [name, index % 2])
        .map(([name, num]) => );

why is name and num in the last line of type string | number obviously inferred as an Array of strings and numbers and do any of you know if there is a way to use type inference so that name is a string and num is a number respectively?

Upvotes: 8

Views: 7914

Answers (2)

bela53
bela53

Reputation: 3485

You can use a const assertion:

['List', 'Of', 'Names']
    .map((name, index) => [name, index % 2] as const) // insert `as const` here
    .map(([name, num]) => { }); // name: string, num: number

Take a look at the playground sample.

Upvotes: 19

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249556

For arrays literals type inference does not infer tuples, it infers arrays, so

var foo = ["", 0]; // foo is Array<string | number> not [string, number]

I have not found documentation on this but the pull request adding support for tuples never uses inference when declaring them, I'm guessing this is deliberate.

In your case you can specify the type parameter:

['List', 'Of', 'Names']
        .map<[string, number]>((name, index) => [name, index % 2])
        .map(([name, num]) => name + "");

2.9 and below solution

Or create a tuple helper function if this is a common issue for you:

function tuple<T1, T2, T3, T4, T5>(data: [T1, T2, T3, T4, T5]) : typeof data
function tuple<T1, T2, T3, T4>(data: [T1, T2, T3, T4]) : typeof data
function tuple<T1, T2, T3>(data: [T1, T2, T3]) : typeof data
function tuple<T1, T2>(data: [T1, T2]) : typeof data
function tuple(data: Array<any>){
    return data;
}

['List', 'Of', 'Names']
        .map((name, index) => tuple([name, index % 2]))
        .map(([name, num]) => name + "");

3.0 Solution

Since I posted the original answer typescript has improved it's inference with the ability to infer tuple types for rest parameters. See PR for details. With this feature we can write a shorter version of the tuple function :

function tuple<T extends any[]> (...data: T){
    return data;
}

['List', 'Of', 'Names']
        .map((name, index) => tuple(name, index % 2))
        .map(([name, num]) => name + "");

Upvotes: 13

Related Questions