我有一个歧视性工会类型Actions。对于每个操作,我有一个不同的处理函数,返回不同的结果。我现在需要一个通用处理程序函数,该函数基于action.type调用相应的处理程序函数并返回其结果。该函数的类型签名应该使得 TypeScript 可以根据调用的参数推断结果的形状。我通过类型签名来实现这一点const handler = <A extends Action>(a: A): HandlerMap[A['type']] => ...。然而,TypeScript 在实现的 switch 语句中抱怨返回无效:
Type 'Result1' is not assignable to type 'HandlerMap[A["type"]]'.
Type 'Result1' is not assignable to type 'Result1 & Result2'.
Type 'Result1' is not assignable to type 'Result2'.
Run Code Online (Sandbox Code Playgroud)
我错过了什么/做错了什么?
这是完整的代码:
type Action1 = { type: 'A1'; input: { i: string } }
type Result1 = { result: string }
const handler1 = (a: Action1): Result1 => ({ result: a.input.i + '!' })
type Action2 = { type: 'A2'; input: { x: number } }
type Result2 = { result: { r2: number } }
const handler2 = (a: Action2): Result2 => ({ result: { r2: a.input.x + 1 } })
type Action = Action1 | Action2
type HandlerMap = {
A1: Result1
A2: Result2
}
const handler = <A extends Action>(a: A): HandlerMap[A['type']] => {
switch (a.type) {
case 'A1': return handler1(a) // <--Compiler complains here
case 'A2': return handler2(a)
default: return undefined
}
}
Run Code Online (Sandbox Code Playgroud)
我会添加这种方法:
const handler = <A extends Action>(a: A): HandlerMap[A['type']] => {
const map: {
[K in keyof HandlerMap]: (a: Extract<Action, { type: K }>) => HandlerMap[K]
} = {
"A1": (a) => handler1(a),
"A2": (a) => handler2(a),
}
return map[a.type](a as any) as HandlerMap[A["type"]]
}
Run Code Online (Sandbox Code Playgroud)
switch我们可以用一个名为 的对象替换map。K该对象包含每个键type和回调。此回调的返回类型严格键入为HandlerMap[K]。
优点:
map是详尽的,如果你忘记处理一个案例,将会给出一个编译时错误a都被严格指定为正确的Action类型。所以a.input.i在第一个回调中可以做类似的事情handler1(a)在第二个回调中返回将导致编译时错误缺点:
我们必须as any在 return 语句中使用(感谢相关的 union 问题)
as HandlerMap[A["type"]]由于 TypeScript 急于解析 tomap[a.type]()而Result1 | Result2不是 ,我们还必须使用{ "A1": ..., "A2": ... }[A["type"]](A)。
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |