Reputation: 1997
So I have a union of tuples, and I can use it to declare locals:
type KnownPair = ["dog", "paws"] | ["fish", "scales"];
const goodPair: KnownPair = ["dog", "paws"];
//@ts-expect-error you can't mix them:
const badPair: KnownPair = ["dog", "scales"];
I want to declare a function that uses the type to describe multiple parameters. I can do it 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 can't mix these, either:
const badCall = foo("fish", "paws");
But when I try to use conventional function parameters, it gets interesting:
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's like each function parameter is individually checked against each case of the union. What's going on? Is it possible to declare bar
in a way that enforces as well as foo
?
References:
Upvotes: 1
Views: 160
Reputation: 175335
The problem with
function bar<T extends KnownPair>(a: T[0], b: T[1]) {
is T[0]
is 'dog | 'fish'
and T[1]
is 'paws' | 'scales'
, but nothing in the type information tells Typescript that they're related. I think the easiest fix is to still use your spread parameters solution, but destructure them into separate variables:
function bar<T extends KnownPair>(...[a, b]: T) {
console.log(`${a} has ${b}`);
}
Upvotes: 1