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

如何让TypeScript函数正确推断返回类型?

如何让TypeScript函数正确推断返回类型?

嘿,我来帮你捋捋这个问题!你遇到的是TypeScript泛型推断里的典型坑——你的doSomething函数里泛型参数的关联不够明确,加上构造函数的类型定义太宽泛,导致TS没法精准推断出返回值是CustomBar<CustomFoo>,反而只识别成了基类Bar<CustomFoo>。

先拆解下问题根源:

  • 你给BarConstructor定义的类型是{ new(...args : any[]): B; },这个any[]直接模糊了构造函数的参数要求,而且TS没法把B和传入的CustomBar的泛型参数F绑定起来。
  • 调用new BarConstructor({})其实也不符合CustomBar的构造规则,它明明需要foo和customField两个参数,只是any[]把这个错误给掩盖了。

下面给你两个可行的解决方案,按需选择:

方案一:通用适配任意Bar子类

我们要让泛型参数的依赖关系更清晰,同时用TypeScript内置的ConstructorParameters工具类型来准确获取构造函数的参数类型,让TS能自动完成正确推断:

class Foo {
  name: string;

  constructor({name}: {name: string}) {
    this.name = name;
  }
}

class Bar<T extends Foo> {
  foo: T;

  constructor({foo}: {foo: T}) {
    this.foo = foo;
  }
}

class CustomFoo extends Foo {
  xxx: string;

  constructor({
    name,
    xxx,
  }: {
    name: string,
    xxx: string,
  }) {
    super({name});
    this.xxx = xxx;
  }
}

class CustomBar<F extends Foo> extends Bar<F> {
  customField: string;

  constructor({
    foo,
    customField,
  }: {
    foo: F,
    customField: string,
  }) {
    super({foo});
    this.customField = customField;
  }
}

// 调整后的doSomething函数
const doSomething = <F extends Foo, B extends Bar<F>>(
  FooConstructor: new (...args: ConstructorParameters<typeof FooConstructor>) => F,
  BarConstructor: new (...args: ConstructorParameters<typeof BarConstructor>) => B,
  ...barArgs: ConstructorParameters<typeof BarConstructor>
): B => {
  return new BarConstructor(...barArgs);
};

// 调用示例:传入符合要求的参数
const myFoo = new CustomFoo({ name: "测试名称", xxx: "自定义字段" });
const mything = doSomething(CustomFoo, CustomBar, { foo: myFoo, customField: "测试自定义值" });

现在mything的类型就会被正确推断为CustomBar<CustomFoo>了!因为我们明确了BarConstructor返回的是B,传入的CustomBar会让TS自动把B关联到CustomBar<CustomFoo>。

方案二:针对CustomBar的简化版本

如果你的场景只需要适配CustomBar这一种子类,可以用更简洁的写法:

// 简化后的doSomething函数
const doSomething = <F extends Foo>(
  FooConstructor: new (...args: ConstructorParameters<typeof FooConstructor>) => F,
  BarConstructor: new (args: { foo: F; customField: string }) => CustomBar<F>,
  fooArgs: ConstructorParameters<typeof FooConstructor>,
  customField: string
): CustomBar<F> => {
  const foo = new FooConstructor(...fooArgs);
  return new BarConstructor({ foo, customField });
};

// 调用示例
const mything = doSomething(CustomFoo, CustomBar, { name: "测试名称", xxx: "自定义字段" }, "测试自定义值");

这个写法更直接,适合不需要兼容多种Bar子类的场景。

最后总结下核心要点:

  • 别用any[]模糊构造函数的参数类型,让TS能准确关联泛型参数
  • 明确泛型之间的继承/依赖关系,给TS足够的推断依据
  • 调用构造函数时一定要传入符合要求的参数,别依赖any掩盖错误

备注:内容来源于stack exchange,提问作者SweetSour

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 07:43:01