You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

代码说明

  1. 通过定义Uninitialized、HasT、HasS、HasBoth四种状态类型,跟踪当前已推断出的泛型参数:
    • Uninitialized:初始状态,未推断任何泛型
    • HasT<T>:已通过a方法推断出T类型
    • HasS<S>:已通过b方法推断出S类型
    • HasBoth<T, S>:两种泛型都已推断完成
  2. 每个方法调用后,返回对应状态的对象,让TypeScript能根据方法参数自动推断泛型,并约束后续方法的返回类型
  3. 内部用变量t和s存储实际值,保证逻辑和原代码一致

这样就无需提前指定fn的泛型参数,完全通过方法调用的参数自动推断类型,满足需求。

内容的提问来源于stack exchange,提问作者TrevTheDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:27:16