如何不使用ts-ignore或额外JS消除此处TypeScript报错?
TypeScript联合类型调用对应函数的类型错误解决方法
问题背景
可以接受TypeScript类型技巧操作,但不想为了满足TypeScript而编写额外的JavaScript代码。当前代码中调用fs[q.format](q)时出现TypeScript错误,需要在不使用// @ts-ignore或额外JS代码的前提下解决。
原代码如下:
interface F1 { format: 1; a: number }; interface F2 { format: 2; a: number; b: number }; function f1(a1: F1) {}; function f2(a2: F2) {}; const fs = { 1: f1, 2: f2 }; const q1: F1 = { format: 1, a: 10 }; const q2: F2 = { format: 2, a: 10, b: 20 }; // 实际值来自外部,无法被TypeScript自动推断类型 const q: F1|F2 = Math.random() > 0.5 ? { format: 2, a: 10, b: 30 } : { format: 1, a: 30 }; f1(q1); // 👍🏼 f2(q2); // 👍🏼 fs[q1.format](q1); // 👍🏼 fs[q2.format](q2); // 👍🏼 fs[q.format](q); // TypeScript错误 ❌
解决方案
方案1:给fs定义精确的映射类型
通过定义关联format值与对应参数类型的映射类型,让TypeScript能正确识别函数与参数的匹配关系,从根源解决类型错误:
interface F1 { format: 1; a: number }; interface F2 { format: 2; a: number; b: number }; function f1(a1: F1) {}; function f2(a2: F2) {}; // 定义所有格式的联合类型 type FormatUnion = F1 | F2; // 定义映射类型:将每个format值对应到接收对应接口的函数 type FormatHandlerMap = { [K in FormatUnion['format']]: (arg: Extract<FormatUnion, { format: K }>) => void; }; // 给fs指定精确的映射类型 const fs: FormatHandlerMap = { 1: f1, 2: f2 }; const q1: F1 = { format: 1, a: 10 }; const q2: F2 = { format: 2, a: 10, b: 20 }; const q: FormatUnion = Math.random() > 0.5 ? { format: 2, a: 10, b: 30 } : { format: 1, a: 30 }; fs[q.format](q); // 类型检查通过 ✅
方案2:调用时用泛型辅助类型缩小
如果不想修改fs的类型定义,可以通过泛型函数辅助TypeScript缩小参数类型范围,无额外JS代码:
// 基于原代码,添加泛型调用函数 type FormatUnion = F1 | F2; function invokeHandler<Q extends FormatUnion>(q: Q) { fs[q.format](q as Extract<FormatUnion, { format: Q['format'] }>); } invokeHandler(q); // 类型检查通过 ✅
或者直接使用inline断言写法:
(fs[q.format] as (arg: typeof q) => void)(q); // 类型检查通过 ✅
内容的提问来源于stack exchange,提问作者Floris
相关产品推荐
相关产品推荐

