This is odd behavior:
const fns = [
(): number => 1,
(): string => '12345',
(): Date => new Date(),
]
type e = ReturnType<typeof fns[0]> //string | number | Date
It's the expected behavior. Typescript will not infer tuple types for an array literal by default, it will infer an array. Given that fns has to be an array, the type of an item in the array has to be a union of all item types in the array literal. So the type of fns is Array< (() => number) | (() => string) | (() => Date))>. This means that as far as TS is concerned the type of any item (be it at index 0 or any other index) will (() => number) | (() => string) | (() => Date)).
ReturnType is a conditional type, its behavior distributes over unions, so when applied to the union (() => number) | (() => string) | (() => Date)) it will extract the return value of each member of the union and the result will be the union of all return values.
If you want to preserve the exact type of fns[0] you will need to convince the compiler to infer a tuple type. This can be done in 3.4 using const, although that will make the tuple readonly
const fns = [ //types as readonly [() => number, () => string, () => Date]
(): number => 1,
(): string => '12345',
(): Date => new Date(),
] as const
type e = ReturnType<typeof fns[0]> //number
Or you can use an extra function:
function tuple<T extends Array<any>>(...t: T){
return t
}
const fns = tuple( // typed as [() => number, () => string, () => Date]
(): number => 1,
(): string => '12345',
(): Date => new Date(),
)
type e = ReturnType<typeof fns[0]> //number
Thanks for the nice responses today @dragomirtitian 馃憤 馃憤 馃憤
Most helpful comment
It's the expected behavior. Typescript will not infer tuple types for an array literal by default, it will infer an array. Given that
fnshas to be an array, the type of an item in the array has to be a union of all item types in the array literal. So the type offnsisArray< (() => number) | (() => string) | (() => Date))>. This means that as far as TS is concerned the type of any item (be it at index0or any other index) will(() => number) | (() => string) | (() => Date)).ReturnTypeis a conditional type, its behavior distributes over unions, so when applied to the union(() => number) | (() => string) | (() => Date))it will extract the return value of each member of the union and the result will be the union of all return values.If you want to preserve the exact type of
fns[0]you will need to convince the compiler to infer a tuple type. This can be done in3.4usingconst, although that will make the tuplereadonlyOr you can use an extra function: