TypeScript能否延迟推断泛型,调用方法后自动更新泛型类型?
解决方案:延迟泛型推断到方法调用时刻
原代码的问题在于调用fn()时,因为没有传入任何触发泛型推断的参数,TypeScript会直接将T和S推断为unknown,后续调用a或b方法时无法再修改这两个泛型的类型,导致baz的类型始终是unknown。
要实现调用foo.a('aString')后自动推断T的类型,让foo.b()的返回类型变为string,需要把泛型参数的推断时机从fn()初始化延迟到a/b方法的调用时刻。以下是可行的实现方式:
// 定义不同状态的类型,跟踪已推断的泛型 type Uninitialized = { a: <T>(arg: T) => HasT<T>; b: <S>(arg: S) => HasS<S>; }; type HasT<T> = { a: <Z extends T = T>(arg: Z) => HasT<Z>; b: <S>(arg: S) => HasBoth<T, S>; }; type HasS<S> = { a: <T>(arg: T) => HasBoth<T, S>; b: <V extends S = S>(arg: V) => HasS<V>; }; type HasBoth<T, S> = { a: <Z extends T = T>(arg: Z) => HasBoth<Z, S>; b: <V extends S = S>(arg: V) => T; }; const fn = (): Uninitialized => { let t: unknown; let s: unknown; return { a: (arg) => { t = arg; return { a: (newArg) => { t = newArg; return fn().a(newArg) as HasT<typeof newArg>; }, b: (argS) => { s = argS; return { a: (newArgT) => { t = newArgT; return fn().a(newArgT).b(argS) as HasBoth<typeof newArgT, typeof argS>; }, b: (newArgS) => { s = newArgS; return t as typeof t; } } as HasBoth<typeof arg, typeof argS>; } } as HasT<typeof arg>; }, b: (arg) => { s = arg; return { b: (newArg) => { s = newArg; return fn().b(newArg) as HasS<typeof newArg>; }, a: (argT) => { t = argT; return { a: (newArgT) => { t = newArgT; return s as typeof s; }, b: (newArgS) => { s = newArgS; return fn().b(newArgS).a(argT) as HasBoth<typeof argT, typeof newArgS>; } } as HasBoth<typeof argT, typeof arg>; } } as HasS<typeof arg>; } }; }; // 测试场景1:先调用a,再调用b const foo = fn(); const fooAfterA = foo.a('aString'); const baz = fooAfterA.b('aString'); // baz类型为string // 再次调用b,返回类型仍为string const baz2 = fooAfterA.b('anotherString'); // baz2类型为string // 测试场景2:先调用b,再调用a const foo2 = fn(); const fooAfterB = foo2.b('testS'); const bar2 = fooAfterB.a('testT'); // bar2类型为string
代码说明
- 通过定义
Uninitialized、HasT、HasS、HasBoth四种状态类型,跟踪当前已推断出的泛型参数:Uninitialized:初始状态,未推断任何泛型HasT<T>:已通过a方法推断出T类型HasS<S>:已通过b方法推断出S类型HasBoth<T, S>:两种泛型都已推断完成
- 每个方法调用后,返回对应状态的对象,让TypeScript能根据方法参数自动推断泛型,并约束后续方法的返回类型
- 内部用变量
t和s存储实际值,保证逻辑和原代码一致
这样就无需提前指定fn的泛型参数,完全通过方法调用的参数自动推断类型,满足需求。
内容的提问来源于stack exchange,提问作者TrevTheDev
相关产品推荐
相关产品推荐

