TypeScript:可区分联合的通用 switchExpression 函数
TypeScript: General switchExpression function for discriminated unions
我正在尝试制作一个通用的 switch 表达式函数,它可以采用任何可区分的联合类型(为简单起见,使用类型 属性 作为鉴别器)及其鉴别器值到回调函数的映射和return 适当回调的结果。
例如
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
});
我们可以使用映射类型和条件类型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
});
我正在尝试制作一个通用的 switch 表达式函数,它可以采用任何可区分的联合类型(为简单起见,使用类型 属性 作为鉴别器)及其鉴别器值到回调函数的映射和return 适当回调的结果。
例如
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
});
我们可以使用映射类型和条件类型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
});