如何让TypeScript函数根据传入参数动态匹配返回类型?
问题描述
现有如下4个类:
class PutCommand { // TODO } class PutCommandOutput { // TODO } class DeleteCommand { // TODO } class DeleteCommandOutput { // TODO }
需要实现一个executeCommand函数,接受PutCommand或DeleteCommand实例作为参数,返回对应的PutCommandOutput或DeleteCommandOutput类型。
最初的实现返回联合类型,调用后必须手动判断返回值类型:
function executeCommand(command: PutCommand|DeleteCommand): PutCommandOutput|DeleteCommandOutput { // TODO: }
调用示例:
const output = executeCommand(command); if (output instanceof PutCommandOutput) { // 处理PutCommandOutput逻辑 } else { // 处理DeleteCommandOutput逻辑 }
尝试泛型写法后,仍需显式指定返回类型,不够便捷:
function executeCommand<T>(command: PutCommand|DeleteCommand): T { // TODO: }
调用示例:
const output = executeCommand<DeleteCommandOutput>(command);
希望实现更智能的类型推导:传入PutCommand实例时,返回类型自动为PutCommandOutput,无需手动指定或判断,直接调用对应类的方法。
解决方案
有两种常用方式可以实现自动类型推导:
方式一:函数重载
通过定义函数重载签名,让TypeScript根据传入的参数类型自动匹配返回类型:
// 重载签名:定义不同参数对应的返回类型 function executeCommand(command: PutCommand): PutCommandOutput; function executeCommand(command: DeleteCommand): DeleteCommandOutput; // 函数实现 function executeCommand(command: PutCommand | DeleteCommand): PutCommandOutput | DeleteCommandOutput { // 实际执行逻辑 if (command instanceof PutCommand) { return new PutCommandOutput(); } else { return new DeleteCommandOutput(); } }
方式二:类型映射+泛型
先定义命令与输出的类型映射关系,再通过泛型关联参数与返回值类型,扩展性更强:
// 定义命令到输出的类型映射 type CommandOutputMap = { [Command in PutCommand | DeleteCommand]: Command extends PutCommand ? PutCommandOutput : DeleteCommandOutput; }; // 泛型函数实现 function executeCommand<T extends PutCommand | DeleteCommand>(command: T): CommandOutputMap[T] { if (command instanceof PutCommand) { return new PutCommandOutput() as CommandOutputMap[T]; } else { return new DeleteCommandOutput() as CommandOutputMap[T]; } }
效果验证
调用时无需额外操作,TypeScript会自动推导返回类型:
const putCmd = new PutCommand(); const putOutput = executeCommand(putCmd); // putOutput 类型自动推导为 PutCommandOutput // 可直接调用PutCommandOutput的方法 const deleteCmd = new DeleteCommand(); const deleteOutput = executeCommand(deleteCmd); // deleteOutput 类型自动推导为 DeleteCommandOutput // 可直接调用DeleteCommandOutput的方法
内容的提问来源于stack exchange,提问作者Wai Yan Hein
相关产品推荐
相关产品推荐

