automatically type inference for tuple arrays
Currently, TypeScript is not able to automatically infer the type of an array of tuples.
For example:
const data = [
['name', 'Luiz Felipe', true],
['age', 16, false]
];
In the above example, TypeScript will infer the type of the data variable as:
(string | boolean)[]
But I think that it should have inferred to:
[string, string, boolean][]
I know that I could have defined the types explicitly in the variable declaration, but I suggest that TypeScript implements this automatic inference system in tuple arrays.
This lack of tuple arrays type inference really annoys me when I need to do something like that:
[
['accessToken', tokens.accessToken, ms('15m')],
['refreshToken', tokens.refreshToken, ms('90 days')]
].forEach(([key, val, maxAge]) => res.cookie(key, val, { maxAge }));
Because key, val and maxAge are incorrectly typed as string | number.
My suggestion meets these guidelines:
as const?
This wouldn't be a breaking change in existing TypeScript/JavaScript code
It absolutely would break tons of existing TypeScript code.
I don't know if this is related, but I have this example:

Although this might very well be an issue with Jest.
Property expectedIcon does not exist on type string
There's already as const; for any given value there's an infinite number of correct types that could be inferred which satisfy those values but it's impossible to know which you intended. The existing options (as const or heterogeneous arrays) are located on two reasonable extremes and it's probably not possible to introduce more in-between types in a way that's more ergonomic than the extant ways of adding type annotations.
I see... Thanks for the feedback, guys! :)
@lffg I think that in these cases there is room for some helper functions to make it clear what the intent of the code is. Like Ryan said, there are an infinite number of ways to type that array, but if we want a tuple array this function would do that:
const data = tupleArray(
['name', 'Luiz Felipe', true],
['age', 16, false]
);
data .forEach(([p, v, e]) => {
// p is string
// v is number | string
// e is boolean
});
function tupleArray<T extends Array<[any] | any[]>>(...a: T): T[number][] {
return a;
}
Or if we want literal types:
const data = tupleLiteralArray(
['name', 'Luiz Felipe', true],
['age', 16, false]
) // (["name", "Luiz Felipe", true] | ["age", 16, false])[]
data.forEach(([p, v, e]) => {
// p 'name' | 'age'
// v 'Luiz Felipe' | 16
// e: boolean
});
function tupleLiteralArray<T extends Array<[V] | V[]>, V extends string | number | boolean | null | undefined | object>(...a: T): T[number][] {
return a;
}
as const is always an option, but the applying it to the whole array makes the whole array a readonly tuple (which is not always intended) and applying it to each tuple in the arrays seems tedious and error prone. Using a function makes intent clear (the name you give can suggest the type being inferred) and potentially removes the as const assertion from a lot of places.
Property
expectedIcondoes not exist on typestring
I know, but string is the first param, it should know I'm using the second param.
Most helpful comment
as const?