如何基于TypeScript泛型参数确定函数另一参数的正确类型?
问题分析
你遇到的问题是TypeScript无法在函数内部通过input的类型判断自动推导options的对应类型,核心原因在于泛型参数T是函数调用时确定的类型,函数内部的类型守卫(比如typeof input === 'number')只能缩小input的类型范围,但无法反向约束泛型T的具体类型,因此条件类型T extends string ? OptionsString : OptionsNumber不会跟着input的类型判断同步缩小。
解决方案
可以通过两种方式解决这个问题:
方案一:使用函数重载
函数重载能明确指定不同输入类型对应的参数组合,让TypeScript直接关联input和options的类型:
type OptionsNumber = { numberProp: number } type OptionsString = { stringProp: string } // 重载签名 export function test(input: number | null | undefined, options?: OptionsNumber): void; export function test(input: string | null | undefined, options?: OptionsString): void; // 实现签名 export function test( input: string | number | null | undefined, options?: OptionsString | OptionsNumber ): void { if (typeof input === 'number') { // 此时TypeScript能正确推断options为OptionsNumber console.log(options?.numberProp); } else if (typeof input === 'string') { console.log(options?.stringProp); } }
方案二:使用联合类型的参数元组
将input和options打包成一个联合类型的元组,让TypeScript通过元组的关联性来推导类型:
type OptionsNumber = { numberProp: number } type OptionsString = { stringProp: string } type TestParams = | [input: number | null | undefined, options?: OptionsNumber] | [input: string | null | undefined, options?: OptionsString] export const test = (...[input, options]: TestParams): void => { if (typeof input === 'number') { console.log(options?.numberProp); } else if (typeof input === 'string') { console.log(options?.stringProp); } }
为什么原代码不生效?
原代码中的泛型条件类型是基于调用时的泛型参数T来计算options的类型,而不是基于函数内部input的实际类型。比如当调用test(123, {numberProp: 456})时,T被推断为number,此时options的类型是OptionsNumber;但函数内部的typeof input === 'number'只是确认了input的类型是number,但TypeScript不会把这个判断和泛型T的类型绑定,所以无法推断options的具体类型。
内容的提问来源于stack exchange,提问作者Nicolas Bouvrette
相关产品推荐
相关产品推荐

