Typescript: Tuples in generic function arguments widens to unions

Created on 6 Feb 2019  路  3Comments  路  Source: microsoft/TypeScript

I'm sorry if this is a duplicate but I wasn't able to find any related issues.

TypeScript Version: 3.4.0-dev.20190206

Search Terms:

tuple generic function arguments params widens union

Code

function foo<T>(tuple: T): T {
    return tuple;
}

const ret = foo([1, "s"]);

Expected behavior:

ret has tuple type of [number, string]

Actual behavior:

It has (string | number)[]

Playground Link: https://www.typescriptlang.org/play/#src=function%20foo%3CT%3E(tuple%3A%20T)%3A%20T%20%7B%0A%20%20%20%20return%20tuple%3B%0A%7D%0A%0Aconst%20ret%20%3D%20foo(%5B1%2C%20%22s%22%5D)%3B>

Motivation

I tried to create React hook which works like this

const result = useMapState((state, arg1, arg2) => {
// ...
}, [1, "ding"]);

I wasn't able to create a type that spreads the tuple to the function arguments correctly.

Most helpful comment

@epeli I wish I could find the issue, but I read it in an issue here. The basic idea was that [any] puts the compiler in the mood for tuples (as its a tuple with a single element) but it will not fail to infer T if the tuple has more elements as that still extends any[]

All 3 comments

Typescript will not infer tuples if it doesn't have to. A constraint of T extends [any] | any[] will make the compiler infer a tuple:

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

const ret = foo([1, "s"]); //tuple now

Also works for your motivating example :

declare function useMapState<A extends [any] | any[]>(fn: (state: {}, ...a: A) => void, a: A): {}
const result = useMapState((state, arg1, arg2) => { //arg1 number, arg2 string 

}, [1, "ding"]);

Ooh, thank you. That works perfectly.

But I must admit I'm pretty confused. Could explain why [any] | any[] causes tuple inference to occur?

@epeli I wish I could find the issue, but I read it in an issue here. The basic idea was that [any] puts the compiler in the mood for tuples (as its a tuple with a single element) but it will not fail to infer T if the tuple has more elements as that still extends any[]

Was this page helpful?
0 / 5 - 0 ratings

Related issues

uber5001 picture uber5001  路  3Comments

siddjain picture siddjain  路  3Comments

jbondc picture jbondc  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

DanielRosenwasser picture DanielRosenwasser  路  3Comments