如何移除TypeScript带条件类型的映射函数中的类型断言?
如何移除TypeScript带条件类型的映射函数中的类型断言?
嗨,这个问题我之前也踩过坑!TypeScript对泛型条件类型的控制流分析确实有点“不开窍”,不过有两种靠谱的方法能去掉那些烦人的类型断言:
方法一:用函数重载明确输入输出对应关系
函数重载可以直接给编译器指明每种输入类型对应的输出类型,完全不需要依赖类型断言,类型安全拉满:
type V0Input = { version: '0' }; type V1Input = { version: '1' } type AnyInput = V0Input | V1Input; type V0Output = { a: string } type V1Output = { b: string } // 先定义重载签名,明确每个输入对应的输出 function fn(i: V0Input): V0Output; function fn(i: V1Input): V1Output; // 然后是实现签名,处理实际逻辑 function fn(i: AnyInput): V0Output | V1Output { if (i.version === '0') { return { a: '' }; } else { return { b: '' }; } }
当你调用fn({ version: '0' })时,TypeScript会自动推断返回类型是V0Output,调用体验和原来的泛型版本完全一致,还不用写断言。
方法二:用映射类型绑定版本与输出
如果你更倾向于保留泛型写法,可以用映射类型把版本号和对应的输出类型直接绑定,让编译器通过索引访问自动推导返回类型:
// 先定义版本到输出类型的映射 type VersionOutputMap = { '0': { a: string }, '1': { b: string } }; // 重新定义输入类型,绑定版本为映射的key type VersionInput<V extends keyof VersionOutputMap> = { version: V }; type AnyInput = VersionInput<keyof VersionOutputMap>; const fn = <V extends keyof VersionOutputMap>(i: VersionInput<V>): VersionOutputMap[V] => { switch(i.version) { case '0': return { a: '' }; // 编译器直接知道这里对应VersionOutputMap['0'] case '1': return { b: '' }; // 同理对应VersionOutputMap['1'] default: // 因为V是VersionOutputMap的key,这个分支永远不会走到,用never做穷尽检查 const _exhaustiveCheck: never = i.version; throw new Error(`Unknown version: ${_exhaustiveCheck}`); } };
这种方式的好处是后续新增版本时,只需要在VersionOutputMap里加对应的类型,编译器会自动提示你补充switch分支,扩展性拉满,也完全不需要类型断言。
为什么原来的代码需要断言?
简单来说,TypeScript的控制流分析没办法跟踪泛型I的具体类型分支:当你检查i.version === '0'时,编译器能知道当前i是V0Input,但泛型I是一个抽象的子类型(可能是V0Input或V1Input),编译器没办法把这个条件判断和泛型Ret<I>的结果关联起来,所以只能用断言来“说服”它。
内容来源于stack exchange
相关产品推荐
相关产品推荐

