TypeScript:用于区分联合的通用 switchExpression 函数
我正在尝试创建一个通用的 switch 表达式函数,它可以接受任何带辨别联合类型的值(为了简单起见,使用类型属性作为辨别器)以及一个将其辨别器值映射到回调函数的映射,并返回相应回调函数的结果。
例如
type One = {
type: 'one',
numeric: number
};
type Two = {
type: 'two',
text: string
};
type Union = One | Two;
const union: Union = ... // some appropriate assignment
// The function switchExp should be aware of what the map should
// look like based on the type of its first arg. The argument
// passed to each callback should be properly discriminated based
// on the key in the map.
let result: number | string = switchExp(union, {
one: u => u.numeric, // compiler should know that u is of type One
two: u => u.text // compiler should know that u is of type Two
});
答案#1
我们可以使用映射类型和条件类型ReturnValue来获得所需的效果。然而,在推断函数参数类型的方式上有一个障碍。如果我们尝试在单个函数调用中进行,参数的类型将被识别为any。
例如,这样做不会如预期那样工作:
function switchExp2<T extends { type: string }, R extends { [P in (T["type"]]: (v: Extract<T, { type: P }>) => any }>(u: T, o: R): ReturnType<R[keyof R]> {
return null as any;
}
let result2 = switchExp2(union, {
one: u => u.numeric, // u is implictly tyed as any
two: u => u.text // u is implictly tyed as any
});
编译器尝试从所有可能的地方推断 T,结果只是放弃,而不是得出结论。一个简单的解决方法是先固定 T,然后再为映射对象进行第二次调用:
function switchExp<T extends { type: string }>(u: T) {
return function <R extends { [P in T["type"]]: (v: Extract<T, { type: P }>) => any }>(o: R): ReturnType<R[keyof R]> {
return null as any; // replace with reasonable implementation
}
}
let result: number | string = switchExp(union)({
one: u => u.numeric, //u is of type One
two: u => u.text // u is of type Two
});
