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>
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.
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[]
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 inferTif the tuple has more elements as that still extendsany[]