【问题标题】:Why does Typescript say my type is "assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint"?为什么 Typescript 说我的类型“可分配给类型‘T’的约束,但‘T’可以用不同的约束子类型实例化”?
【发布时间】:2021-01-08 01:33:08
【问题描述】:

考虑以下 Typescript 代码:

class OrderFixture {
  orderId: string;

  constructor() {
    this.orderId = "foo";
  }
}

class DecisionFixture {
  decisionId: string;

  constructor() {
    this.decisionId = "bar";
  }
}

class FixtureStore {
  order = () => new OrderFixture();
  decision = () => new DecisionFixture();
}

const fixtureStore = new FixtureStore();

export function getFixture<
  K extends keyof FixtureStore,
  T extends ReturnType<FixtureStore[K]>
>(entityName: K): T {
  return fixtureStore[entityName](); // ERROR: Type 'OrderFixture' is not assignable to type 'T'.
}

它会产生以下类型错误:

Type 'OrderFixture | DecisionFixture' is not assignable to type 'T'.
  'OrderFixture | DecisionFixture' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'OrderFixture | DecisionFixture'.
    Type 'OrderFixture' is not assignable to type 'T'.
      'OrderFixture' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'OrderFixture | DecisionFixture'.ts(2322)

这是playground

这种类型的错误引发的问题似乎有一个fairly canonical answer,但我看不出那里列出的两个原因与我的代码之间有任何相关的相似之处。

如果我按照this answer 中的建议强制将返回值转换为T,我在调用getFixture 时会得到正确的类型。为什么 Typescript 不为我推断这些类型?

【问题讨论】:

  • 这是一个很好的问题,顺便说一下,我以前也遇到过类似的问题。我会这么说是因为推断可以达到OrderFixture | DecisionFixture,但你只会指定其中一个,所以你必须说出它使用类型转换的两个中的哪一个......
  • 如果你转换为any 更奇怪的是,被调用者仍然得到正确的推断类型。嗯

标签: typescript


【解决方案1】:

Typescript 的错误消息在这里是完美的描述:你的函数返回的东西可以分配给OrderFixture | DecisionFixture,但不能分配给它的任意子类型,例如OrderFixture &amp; HTMLCanvasElement。如果您仍然不确定,请考虑以下代码,其中您的函数承诺返回这样的东西;它显然不是类型安全的,但它没有错误,因为它只使用您的函数声称具有的返回类型。

let canvas = getFixture<'order', OrderFixture & HTMLCanvasElement>('order');
let ctx = canvas.getContext('2d');

通常,正是由于这个原因,你不应该有一个只出现在返回位置的类型参数,因为它允许调用者在不传递任何参数的情况下期望一个特定的类型,让函数知道它所期望的类型返回。在您的情况下,不需要类型参数T:只需将ReturnType&lt;FixtureStore[K]&gt; 直接设为函数的返回类型即可。


也就是说,在这种情况下,发生了一些可疑的事情,这似乎确实是 Typescript 的错:即使拆分函数的逻辑并提供类型注释来帮助编译器,Typescript 仍然会出错。

function getFixture<K extends keyof FixtureStore>(entityName: K): ReturnType<FixtureStore[K]> {
  let factory: FixtureStore[K] = fixtureStore[entityName];

  // error here
  let instance: ReturnType<typeof factory> = factory();
  
  return instance;
}}

Playground Link

从逻辑上讲,Typescript 永远不应该抱怨 factory() 的类型可能无法分配给 ReturnType&lt;typeof factory&gt;,但在这里它抱怨的正是这一点。所以我认为这应该由了解 Typescript 内部结构的人来查看,并且可能作为他们的问题跟踪器上的错误提出。

【讨论】:

    猜你喜欢
    • 2019-12-13
    • 2021-12-10
    • 2020-11-25
    • 2022-01-20
    • 2021-06-19
    • 2023-01-11
    • 2021-10-14
    • 2021-02-13
    • 2021-05-22
    相关资源
    最近更新 更多