TypeScript中如何通过条件参数反向推导缩小泛型T的类型范围
解决方案
最优方案是使用函数重载实现该需求,TypeScript当前版本不支持通过参数条件类型的判断反向收窄泛型约束范围,重载可以完全规避这个问题,同时保留甚至优化调用侧的使用体验。
完整实现代码
// 重载签名1:传入id时,返回单个Item类型 function foo<T extends Item>(id: string): T; // 重载签名2:不传id时,返回Item数组类型 function foo<T extends Item[]>(): T; // 实现签名仅对内可见,不需要复杂的条件类型定义 function foo(id?: string): Item | Item[] { if (typeof id === 'string') { // 该分支下编译器可自动识别返回值为Item类型,无需额外断言 return fetchSingleItem(id); } // 无id分支自动识别为返回Item数组类型 return fetchItemList(); }
优势说明
- 调用侧完全兼容原有写法:
foo<MyItem>('42')和foo<MyItem[]>()都可以正常使用 - 支持自动类型推导:调用时不需要显式声明泛型,
const item = foo('42')自动推导为Item类型,const list = foo()自动推导为Item[]类型 - 不需要在实现体内加任何类型断言,完全符合类型安全要求
如果要保留可变参数的无参调用优化,可以调整实现为:
function foo<T extends Item>(id: string): T; function foo<T extends Item[]>(): T; function foo(...args: [string] | []): Item | Item[] { if (args.length === 1) { return fetchSingleItem(args[0]); } return fetchItemList(); }
该写法可以避免调用时误传undefined的问题,更加安全。
内容的提问来源于stack exchange,提问作者JHH
相关产品推荐
相关产品推荐

