【问题标题】:typescript: Infer generic requirement of type打字稿:推断类型的通用要求
【发布时间】:2020-07-21 07:30:51
【问题描述】:

问题

您如何推断泛型类的泛型要求(扩展部分中的内容)?

说明

// UserGivenClassThatCouldHaveAnyGeneric
class A<T extends string> {
  constructor(a: T) {}
}

我如何推断通用T 必须扩展string。我需要在条件语句中使用此信息。

我已经尝试了以下

type E<W> = any extends A<infer T> ? W extends T ? A<W> : void : void

E 在给定 W 不扩展 T 所要求的内容时应为 void,但在其扩展时应为 A。然而这根本不起作用,尽管没有显示语法错误警告。

【问题讨论】:

  • 可能喜欢this?让我知道这是否适合您,如果适合,我会写下来;否则,请说明它如何无法满足您的需求。祝你好运。
  • @jcalz 是的,非常感谢!没有元组也不行吗?喜欢this
  • 视情况而定;你想让E&lt;"a" | "b"&gt; 成为A&lt;"a" | "b"&gt; 还是A&lt;"a"&gt; | A&lt;"b"&gt;

标签: typescript generics type-inference


【解决方案1】:

我的建议是将E&lt;W&gt; 更改为这样的:

type E<W> = never extends A<infer T> ? [W] extends [T] ? A<W> : void : never

首先,对于大多数类型X,检查类型为any 的条件类型(如any extends X ? Y : Z)最终将被评估为联合Y | Z。也就是说,any 是一种特殊情况,它采用条件类型的两个分支。请参阅microsoft/TypeScript#27418 了解有关此问题的一些讨论。假设你只是想使用条件类型的真正分支,最好使用never extends X ? Y : Z。一般never extends X 总是为真,那么结果就是Y。此外,如果您不想担心会弄乱您的工会,您应该将其设为never,而不是voidA | never 类型的计算结果为 A,而 A | void 通常不会。

所以让我们将type E&lt;W&gt; = any extends A&lt;infer T&gt; ? W extends T ? A&lt;W&gt; : void : void 更改为type E&lt;W&gt; = never extends A&lt;infer T&gt; ? W extends T ? A&lt;W&gt; : void : never


现在剩下的问题是:当W 本身是联合类型时,你想做什么?如果您将E&lt;W&gt; 定义为W extends T 而不是[W] extends [T],它将被视为distributive conditional type。这意味着如果W 是类似A | B | C 的联合类型,那么E&lt;W&gt; 将评估该联合的每个 成员的条件并将结果合并,产生E&lt;A&gt; | E&lt;B&gt; | E&lt;C&gt; 的等价物。也许这就是你想要的,但可能不是。毕竟,如果Wstring | number,你可能希望void 出来,而不是A&lt;string&gt; | void,对吧?

条件类型何时变为可分配的规则是检查“裸”或“裸”泛型类型参数。由于W 是泛型类型参数,因此条件类型W extends T ? ... 将是可分配的。关闭此行为的最简单方法是用协变的东西“覆盖”类型参数,例如单元素元组类型。所以它变成了[W] extends [T] ? ...


好的,希望对您有所帮助;祝你好运!

Playground link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-09
    • 2018-08-12
    • 2020-04-02
    • 2020-12-20
    • 2016-08-03
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多