Reputation: 1
I have two types of string literals:
type U = {
type: "A1",
value: number
} | {
type: "A2",
value: string
};
type V = {
type: "A1",
test: (value: number) => void;
} | {
type: "A2",
test: (value: string) => void;
}
In function resolve(), I'm trying to call method test() with value props from arguments type U:
let resolve = (u: U, v: V) => {
if (u.type === v.type) {
v.test(u.value)
}
}
But got error:
Argument of type 'string | number' is not assignable to parameter of type 'number & string'.
Type 'string' is not assignable to type 'number & string'.
Type 'string' is not assignable to type 'number'.
Some workaround, I have to separate check type into:
let resolve = (u: U, v: V) => {
if ((u.type === "A1" && v.type === "A1")) {
v.test(u.value)
} else if (u.type === "A2" && v.type === "A2") {
v.test(u.value)
}
}
Is it possible to declare a function without checking each of literal types?
Upvotes: 0
Views: 119
Reputation: 249506
Typescript can't track related variables like this (something like jcalz's suggestion of correlated record types would be necessary for this).
The simplest solution is to use a type assertion since you know this to be valid:
let resolve = (u: U, v: V) => {
if (u.type === v.type) {
v.test(u.value as any)
}
}
Or a safer version that asserts to an intersection of value
(this will ensure that all options are covered in U
):
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
let resolve = (u: U, v: V) => {
if (u.type === v.type) {
v.test(u.value as UnionToIntersection<U['value']>)
}
}
Upvotes: 1