使用打字稿3.7。
鉴于此处定义的命令和命令处理程序的标准概念,该处理程序可能是异步的:
export type Command = { name: string; body: any };
export type CommandHandler<TCommand extends Command, TResult = any> = (cmd: TCommand) => TResult | Promise<TResult>;
我正在尝试创建一个函数,给定一个命令处理程序数组,该函数将返回一个新的命令处理程序,该命令处理程序有效地调用每个处理程序顺序地并返回最后执行的处理程序的结果,从而允许任何处理程序中断处理程序链。
我希望这样的事情可以工作:
export const chain = <TCommand extends Command, TResult = any>(
...handlers: CommandHandler<TCommand, TResult>[]
): CommandHandler<TCommand, TResult> => async cmd => {
let result: TResult;
for (const handler of handlers) {
result = await handler(cmd);
}
return result;
};
但是编译器给我这个错误:Variable 'result' is used before being assigned. ts(2454)
为什么不起作用,如何组织该代码?
如果handlers
为空,TypeScript将此理解为let result: TResult; return result
,它返回undefined
。 any
是垃圾,effectively disables TypeScript。
TypeScript在无法确定表达式的类型时会使用类型
any
。与Dynamic
相比,将any
称为类型是一种高估。不管它出现在哪里,它都会关闭类型检查器。
考虑此替代方法-
type Command<T> =
{ name: string; body: T | void }
type CommandHandler<T> =
(cmd: Command<T>) => Promise<T | void>
function chain <T>(...handlers: Array<CommandHandler<T>>): CommandHandler<T>
{ return async (cmd: Command<T>): Promise<T | void> =>
{ let r
for (const h of handlers)
r = await h(cmd)
return r
}
}
因为我们将chain
的返回类型定义为CommandHandler<T>
,所以我们甚至不需要async
函数周围的额外类型提示-
type Command<T> =
{ name: string; body: T | void }
type CommandHandler<T> =
(cmd: Command<T>) => Promise<T | void>
function chain <T>(...handlers: Array<CommandHandler<T>>): CommandHandler<T>
{ return async cmd => // <-- cmd inferred as Command<T>
{ let r
for (const h of handlers)
r = await h(cmd)
return r // <-- inferred T | void
}
}
演示:验证此typescript sandbox中的结果