简体   繁体   中英

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 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?

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 + "");

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM