如何让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
相关产品推荐
相关产品推荐

