How do these types check for true equality between the parameters?

Viewed 72

I feel the conditional types are very powerful. I want to leverage it to do more complex and dynamic checking.

I want to check if given 2 generics are equal.

I saw this solution on Typescript's issues.

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

type res1 = MyEquals<true, false>                         // false, values
type res2 = MyEquals<true, true>                          // true,  values
type res3 = MyEquals<boolean, boolean>                    // true,  primitive types
type res4 = MyEquals<Promise<string>, Promise<string>>    // true,  advanced/custom types

I don't understand why the function <T>() => T notation and the primitives aren't functions so how is this type giving me a true/false on those values.

Can someone explain me how this MyEquals works and does it really work for all types?

Another solution stated in the same issue:

type EqualsWrapped<T> = T extends infer R & {}
    ? {
          [P in keyof R]: R[P]
      }
    : never

export type Equals<A, B> = (<T>() => T extends EqualsWrapped<A> ? 1 : 2) extends
(<T>() => T extends EqualsWrapped<B> ? 1 : 2)
  ? true
  : false

Here I don't understand what does T extends infer R & {} actually do? Isn't extends supposed to do a structural check {a: string} == {a: number}(resulting in false) kind of a check? And infer is supposed to be used to target Item of an Array or Property of an Object, right? So what are we inferring here if T isn't a Object or Array?

Sorry for so many questions.

0 Answers
Related