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

问题描述 投票:0回答:1
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;
  }
}

const doSomething = <
  B extends Bar<F>,
  F extends Foo,
>(
  FooConstructor: { new(...args : any[]): F; },
  BarConstructor: { new(...args : any[]): B; },
): B => {
  return new BarConstructor({});
}

const mything = doSomething(CustomFoo, CustomBar);

不幸的是,

mything
的类型是
Bar<CustomFoo>
,而我要求它是
CustomBar<CustomFoo>

我希望 TypeScript 能够推断出返回类型。

我怎样才能以这样的方式编写

doSomething
,以便它返回推断的类型而不是“基本”类型?

我不知道该尝试什么。

typescript
1个回答
0
投票

不幸的是,TypeScript 的推理不会给你你想要的东西,也没有办法在 TypeScript 中以无缝或通用的方式表达你正在做的事情。 TypeScript 没有 microsoft/TypeScript#40179 中要求的“调用类型”。你会喜欢能够说:给定一些泛型类型的

BarConstructor
,当你调用构造函数时你会得到什么类型,记住它可能是泛型并且取决于它的输入或它的方式叫做。但除非你真的直接调用构造函数,否则无法捕获它。您可以使用条件类型,例如InstanceType
,但这最终会丢失任何泛型。一般限制是围绕更高种类的类型,如 
microsoft/TypeScript#1213 中所要求的。没有很好的方法来处理泛型的泛型。

当您调用

doSomething(CustomFoo, CustomBar)

 时,
F
 被推断为 
CustomFoo
,然后 
B
 必须被推断为 
Bar<CustomFoo>
 的子类型。但 TypeScript 在这里失去了线索;它不能“插入”任何地方,因为这需要更高级的类型。你能得到的最好结果是 
CustomFoo
,但实际发生的情况是它又回到了 
CustomBar<Foo>
 的约束。 TypeScript 的推理在这里只会给你 
Bar<CustomFoo>
CustomBar<Foo>
相反,您需要解决它。在给定的示例中,您可以使用的一种解决方法是在 

Bar<CustomFoo>
上使用

实例化表达式,以告诉编译器您特别关心将 CustomBar

 插入该构造函数的类型参数中:
CustomFoo

现在,当编译器推断
const mything = doSomething(CustomFoo, CustomBar<CustomFoo>);
// const mything: CustomBar<CustomFoo>
时,唯一的选择是

B

,然后一切正常。
Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.