TypeScript:如何传递联合类型参数并保留函数重载签名?
TypeScript重载与联合类型的两个常见问题及解决方法
问题1:子类调用父类重载方法时联合类型参数报错
问题描述
子类Collection的del方法传递联合类型T | ((v: T) => boolean)给父类Enumerable的重载index方法时,TypeScript无法匹配任何一个重载分支,抛出类型错误。
解决方法
TypeScript的重载解析不会自动将联合类型拆分为对应的重载分支,需要手动通过类型守卫区分参数类型,分别匹配重载:
方案1:基础类型守卫(适用于T非函数类型场景)
class Enumerable<T> { index(v: T): number | undefined index(op: (v: T) => boolean): number | undefined index(op: T | ((v: T) => boolean)): number | undefined { return 0 } } class Collection<T> extends Enumerable<T> { del(v: T | ((v: T) => boolean)): void { const i = typeof v === 'function' ? this.index(v as (v: T) => boolean) : this.index(v); console.log(i); } } new Collection<number>().del(0); // 正常运行
方案2:自定义类型守卫(适用于T可能为函数类型场景)
如果泛型T本身可能是函数类型,基础的typeof判断无法区分,需要自定义类型守卫:
function isDeletePredicate<T>(val: T | ((v: T) => boolean)): val is ((v: T) => boolean) { // 可根据实际逻辑添加更严格判断,比如检查参数个数 return typeof val === 'function' && (val as Function).length === 1; } class Collection<T> extends Enumerable<T> { del(v: T | ((v: T) => boolean)): void { const i = isDeletePredicate(v) ? this.index(v) : this.index(v); console.log(i); } }
问题2:联合类型回调参数导致类型推断异常
问题描述
当order方法的参数是联合类型((a: T, b: T) => number) | ((v: T) => unknown)时,传入回调(pairs) => pairs[0]会出现参数隐式any的错误,TypeScript无法推断参数类型。
解决方法
将联合类型参数改为函数重载,让TypeScript根据传入的回调自动匹配对应的重载分支,从而正确推断参数类型:
class Collection<T> { // 重载签名 order(): T[]; order(op: (a: T, b: T) => number): T[]; order(op: (v: T) => unknown): T[]; // 实现签名 order(op?: ((a: T, b: T) => number) | ((v: T) => unknown)): T[] { return []; } } new Collection<[number, number]>() .order((pairs) => pairs[0]); // pairs自动推断为[number, number]
通过重载,TypeScript会识别传入的回调属于(v: T) => unknown分支,进而正确推断pairs的类型为T(即[number, number])。
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

