如何基于推断的请求类型为响应类型添加TypeScript类型标注?
如何基于推断的请求类型为响应类型添加TypeScript类型标注?
这个需求完全可以实现!我来帮你分析下问题出在哪,再给出可行的解决方案~
问题根源
你当前的泛型函数写法里,虽然通过message.action做了分支判断,但TypeScript没办法把泛型T精准收窄到某个具体的请求类型上。它会认为CuteResMap[T['action']]可能涵盖所有响应类型的交集(也就是同时满足两种响应结构的类型),这就导致你传入分支里的具体响应对象时,触发了类型不匹配的报错。
最优解决方案:函数重载
函数重载是最直观且类型安全的实现方式,它能明确告诉TypeScript:当传入某类请求时,对应的响应类型是什么。修改后的代码如下:
// 定义请求类型 interface SetKittenPenRequest { action: 'set-kitten-pen'; count: number; } interface GetPuppyRequest { action: 'get-puppy'; id: string; } // 定义响应类型 interface SetKittenPenResponse { success: boolean; msg: string; } interface GetPuppyResponse { success: boolean; details: { breed: string; age: number }; } // 请求类型联合 type CuteReq = SetKittenPenRequest | GetPuppyRequest; // 响应映射 type CuteResMap = { 'set-kitten-pen': SetKittenPenResponse; 'get-puppy': GetPuppyResponse; }; // 函数重载声明:明确每个请求对应的响应类型 function handleCuteReqs(message: SetKittenPenRequest, sendResponse: (response: SetKittenPenResponse) => void): void; function handleCuteReqs(message: GetPuppyRequest, sendResponse: (response: GetPuppyResponse) => void): void; // 函数实现 function handleCuteReqs(message: CuteReq, sendResponse: (response: CuteResMap[CuteReq['action']]) => void) { if (message.action === 'set-kitten-pen') { const response: SetKittenPenResponse = { success: true, msg: `Kitten pen set for ${message.count} kittens!`, }; sendResponse(response); // 类型完全匹配,不再报错 } else if (message.action === 'get-puppy') { const response: GetPuppyResponse = { success: true, details: { breed: 'Golden Retriever', age: 2 }, }; sendResponse(response); // 类型完全匹配 } }
为什么这个方案有效?
重载声明提前给TypeScript做了“类型约定”:当传入的message是SetKittenPenRequest时,sendResponse的参数必须是SetKittenPenResponse;传入GetPuppyRequest时,对应GetPuppyResponse。在函数实现的分支里,TypeScript能根据message.action正确收窄类型,自然就不会再出现类型不匹配的问题。
备选方案:类型断言(不推荐)
如果不想用重载,也可以通过类型断言强制告诉TypeScript当前分支的响应类型是匹配的,但这种方式会牺牲一部分类型安全性,仅作为临时方案:
function handleCuteReqs<T extends CuteReq>( message: T, sendResponse: (response: CuteResMap[T['action']]) => void ) { if (message.action === 'set-kitten-pen') { const response: SetKittenPenResponse = { success: true, msg: `Kitten pen set for ${message.count} kittens!`, }; sendResponse(response as CuteResMap[T['action']]); } else if (message.action === 'get-puppy') { const response: GetPuppyResponse = { success: true, details: { breed: 'Golden Retriever', age: 2 }, }; sendResponse(response as CuteResMap[T['action']]); } }
综上,函数重载是实现你需求的最佳选择,既保证了类型安全,又能让调用方不用手动查类型映射,TypeScript会自动提示对应的响应类型。
内容来源于stack exchange
相关产品推荐
相关产品推荐

