`Equals` 在打字稿中是如何工作的?

贾亚图比

我在以下位置找到了一个Equals实用程序:https : //github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650

export type Equals<X, Y> =
    (<T>() => T extends X ? 1 : 2) extends
    (<T>() => T extends Y ? 1 : 2) ? true : false;

它可用于检查两种类型是否相等,例如:

type R1 = Equals<{foo:string}, {bar:string}>; // false
type R2 = Equals<number, number>; // true

我很难理解这是如何工作的以及T表达式中的含义。

有人可以解释一下吗?

亚历克斯·查辛

首先让我们添加几个括号

export type Equals<X, Y> =
    (<T>() => (T extends /*1st*/ X ? 1 : 2)) extends /*2nd*/
    (<T>() => (T extends /*3rd*/ Y ? 1 : 2)) 
        ? true 
        : false;

现在,当你代替部分类型XY什么本次extends关键字做基本上是问一个问题:“类型的变量<T>() => (T extends X ? 1 : 2)分配给类型的变量(<T>() => (T extends Y ? 1 : 2))。换句话说?

declare let x: <T>() => (T extends /*1st*/ X ? 1 : 2) // Substitute an actual type for X
declare let y: <T>() => (T extends /*3rd*/ Y ? 1 : 2) // Substitute an actual type for Y
y = x // Should this be an error or not?

您提供的评论的作者说

条件类型 <...> 的可分配性规则要求后面的类型extends与检查器定义的“相同”

他们在这里谈论的是第一个和第三个extends关键字。如果它们之后的类型(即and )相同,则检查器将只允许将x其分配给如果您同时替换两者yXYnumber

declare let x: <T>() => (T extends number ? 1 : 2)
declare let y: <T>() => (T extends number ? 1 : 2)
y = x // Should this be an error or not?

当然它不应该是一个错误,因为有 2 个相同类型的变量。现在,如果你替换numberXstringY

declare let x: <T>() => (T extends number ? 1 : 2)
declare let y: <T>() => (T extends string ? 1 : 2)
y = x // Should this be an error or not?

现在后面extends类型不相同,所以会出现错误。


现在让我们看看为什么后面的类型extends必须相同才能分配变量。如果它们相同,那么一切都应该清楚了,因为您只有 2 个相同类型的变量,它们总是可以相互分配的。至于另一种情况,请考虑我描述的最后一种情况,带有Equals<number, string>. 想象一下这不是错误

declare let x: <T>() => (T extends number ? 1 : 2)
declare let y: <T>() => (T extends string ? 1 : 2)
y = x // Imagine this is fine

考虑这个代码片段:

declare let x: <T>() => (T extends number ? 1 : 2)
declare let y: <T>() => (T extends string ? 1 : 2)

const a = x<string>() // "a" is of type "2" because string doesn't extend number
const b = x<number>() // "b" is of type "1"

const c = y<string>() // "c" is of type "1" because string extends string
const d = y<number>() // "d" is of type "2"

y = x
// According to type declaration of "y" we know, that "e" should be of type "1"
// But we just assigned x to y, and we know that "x" returns "2" in this scenario
// That's not correct
const e = y<string>() 
// Same here, according to "y" type this should be "2", but since "y" is now "x",
// this is actually "1"
const f = y<number>()

如果类型不是stringand number则类似,它们没有任何共同点,但更复杂。让我们试试{foo: string, bar: number}forX{foo: string}for Y请注意,这里X实际上可以分配给Y

declare let x: <T>() => (T extends {foo: string, bar: number} ? 1 : 2)
declare let y: <T>() => (T extends {foo: string} ? 1 : 2)

// "a" is of type "2" because {foo: string} doesn't extend {foo: string, bar: number}
const a = x<{foo: string}>()

// "b" is of type "1"
const b = y<{foo: string}>()

y = x
// According to type declaration of "y" this should be of type "1", but we just
// assigned x to y, and "x" returns "1" in this scenario
const c = y<{foo: string}>()

如果切换类型并尝试{foo: string}forX{foo: string, bar: number}for Y,那么调用y<{foo: string}>(). 你可以看到总是有问题。

更准确地说,如果XY不相同,总会有某种类型扩展其中一个,而不扩展另一个。如果你尝试使用这种类型T的天空坠落到地面上。实际上,如果您尝试分配y = x,编译器会给您这样的错误:

Type '<T>() => T extends number ? 1 : 2' is not assignable to type '<T>() => T extends string ? 1 : 2'.
  Type 'T extends number ? 1 : 2' is not assignable to type 'T extends string ? 1 : 2'.
    Type '1 | 2' is not assignable to type 'T extends string ? 1 : 2'.
      Type '1' is not assignable to type 'T extends string ? 1 : 2'.

因为总有一个类型,它是分配给一XY,而不是其他,它被强制治疗的返回类型x1 | 2,这是不能分配给T extends ... ? 1 : 2,因为T可以是任何东西。

这基本上就是这种Equals类型的归结,希望它或多或少清楚,它是如何工作的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章