【问题标题】:Why this CustomExtract returns an different result from default Extract?为什么此 CustomExtract 返回与默认 Extract 不同的结果?
【发布时间】:2023-01-22 18:48:03
【问题描述】:

代码解释了我的问题:

type A = {
  a: number,
} | null

// Extract as defined in lib.es5.d.ts
type Extract<T, U> = T extends U ? T : never;

type CustomExtract = A extends null ? A : never;

type Result1 = Extract<A, null> // null
type Result2 = CustomExtract;   // never

Extract 和 CustomExtract 是相同的代码,区别在于 Extract 是泛型类型。

此外,作为相关示例,string | null 不会扩展 null

那么,在这个主题中,类型到底是如何工作的呢?我可以想象它可能会为每种类型的联合运行通用类型,然后合并所有结果,但我想要真正的技术定义和它的工作。

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    区别在于 Extractdistributive conditional type,而你的 CustomExtract 不是。

    为了使 X extends Y ? A : B 形式的条件类型具有分配性,检查的类型 X 必须是“裸类型参数”;这是一个类型参数比如Tinterface Foo&lt;T&gt; {...},和因为它只是被检查的类型参数(即T extends ...),而不仅仅是一些包含类型参数的表达式(例如Promise&lt;T&gt; extends ...[T] extends ...)。

    正如您推测的那样,分布式条件类型确实评估为检查类型 T 的每个联合元素的条件联合。因此,如果 F&lt;T&gt; 是分配条件类型,则 F&lt;A | B | C&gt; 将被评估为 F&lt;A&gt; | F&lt;B&gt; | F&lt;C&gt;。一个潜在问题是 F&lt;never&gt; 将被评估为 never 无论 F 的详细信息是什么(只要它是分布式的),因为 never 被认为是 "empty union type"

    有关更多信息,请参阅我的other answer,了解什么是分布式条件类型以及它们如何工作。

    【讨论】:

      【解决方案2】:

      @jcalz 所说的都是正确的,但我会尽量用通俗易懂的英语表达出来。

      Extract&lt;T, U&gt; 所做的是返回子集T 可分配给 U。如果 T 有一些 U 类型和一些其他类型,我们只得到 U 类型。尽管有一个看起来与CustomExtract 相同的定义,但它为何以及如何做到这一点,这就是@jcalz 的答案。

      在您的例子中,type A{a: number}null 的并集。 {a: number}不可分配给null,但null可分配给null。所以可分配给null的子集是null

      type CustomExtract = A extends null ? A : never;永远不会返回一个子集.如果满足条件,则返回完整的A,如果不满足条件,则返回never

      为了使X extends Y 为真,X 的所有值都必须可分配给Y,换句话说,X 必须等于或小于Y

      A extends null 是错误的,因为 Anull 宽。另一方面,null extends A 是真实的。

      【讨论】:

        猜你喜欢
        • 2021-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多