I have a collection of tuples that I can use to define variables:
type KnownPair = ["dog", "paws"] | ["fish", "scales"];
const goodPair: KnownPair = ["dog", "paws"];
//@ts-expect-error you cannot mix them:
const badPair: KnownPair = ["dog", "scales"];
I want to create a function that utilizes the type to describe multiple parameters. This can be achieved with spread syntax:
function foo<T extends KnownPair>(...args: T) {
console.log(`${args[0]} has ${args[1]}`);
}
const goodCall = foo("fish", "scales");
//@ts-expect-error you cannot mix these either:
const badCall = foo("fish", "paws");
However, things get interesting when traditional function parameters are used:
function bar<T extends KnownPair>(a: T[0], b: T[1]) {
console.log(`${a} has ${b}`);
}
const goodCall2 = bar("dog", "paws");
//@ts-expect-error TypeScript rejects a bad explicit type argument:
const badCall2 = bar<["dog","scales">>("dog", "scales");
// but it doesn't see any problems when inferring the type:
const shouldBeBad = bar("dog", "scales");
It seems like each parameter in the function is checked against each case of the union individually. What's happening here? Is there a way to enforce bar
similar to foo
?
References: