Typescript: [Feature request]type level equal operator

Created on 11 Sep 2018  路  13Comments  路  Source: microsoft/TypeScript

Search Terms

  • Type System
  • Equal

Suggestion

T1 == T2

Use Cases

TypeScript type system is highly functional.
Type level testing is required.
However, we can not easily check type equivalence.
I want a type-level equivalence operator there.

It is difficult for users to implement any when they enter.
I implemented it, but I felt it was difficult to judge the equivalence of types including any.

Examples

type A = number == string;// false
type B = 1 == 1;// true
type C = any == 1;// false
type D = 1 | 2 == 1;// false
type E = Head<[1,2,3]> == 1;// true(see:#24897)
type F = any == never;// false
type G = [any] == [number];// false
type H = {x:1}&{y:2} == {x:1,y:2}// true
function assertType<_T extends true>(){}

assertType<Head<[1,2,3]> == 1>();
assertType<Head<[1,2,3]> == 2>();// Type Error

Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. new expression-level syntax)
Question

Most helpful comment

Here's a solution that makes creative use of the assignability rule for conditional types, which requires that the types after extends be "identical" as that is defined by the checker:

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

This passes all the tests from the initial description that I was able to run except H, which fails because the definition of "identical" doesn't allow an intersection type to be identical to an object type with the same properties. (I wasn't able to run test E because I don't have the definition of Head.)

All 13 comments

Here's a working implementation:

/**
 * Tests if two types are equal
 */
export type Equals<T, S> =
    [T] extends [S] ? (
        [S] extends [T] ? true : false
    ) : false
;

The only problem is that any is "equal to" everything, except never.

@AlCalzone
I know that.(https://github.com/kgtkr/typepark/blob/master/src/test.ts)
There is a problem of not being able to judge any.

example:

type X=Equals<{x:any},{x:number}>;//true

any is not assignable to never, so you should be able to determine whether or not either side is exclusively any.

Here's a solution that makes creative use of the assignability rule for conditional types, which requires that the types after extends be "identical" as that is defined by the checker:

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

This passes all the tests from the initial description that I was able to run except H, which fails because the definition of "identical" doesn't allow an intersection type to be identical to an object type with the same properties. (I wasn't able to run test E because I don't have the definition of Head.)

Thank you
There was a way

The best solution I have to date: spec.ts

Examples

Here's a solution that makes creative use of the assignability rule for conditional types, which requires that the types after extends be "identical" as that is defined by the checker:

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

This passes all the tests from the initial description that I was able to run except H, which fails because the definition of "identical" doesn't allow an intersection type to be identical to an object type with the same properties. (I wasn't able to run test E because I don't have the definition of Head.)

It work, but how?
Could you provide more explanation?
I try to explain it though by Typescript's bivariant behavior or something else.
But I failed, help, pls.

@jituanlin AFAIK it relies on conditional types being deferred when T is not known. Assignability of deferred conditional types relies on an internal isTypeIdenticalTo check, which is only true for two conditional types if:

  • Both conditional types have the same constraint
  • The true and false branches of both conditions are the same type

@AlCalzone It seems that function overloads do not work.

type F = (x: 0, y: null) => void
type G = (x: number, y: string) => void

type EqEq<T, S> = [T] extends [S] ? ([S] extends [T] ? true : false) : false

// Function type intersection is defined as overloads in TypeScript.
type OF1 = EqEq<F & G, G & F> // true
type OF3 = EqEq<{ (x: 0, y: null): void; (x: number, y: null): void }, { (x: number, y: null): void; (x: 0, y: null): void }> // true

@mattmccutchen

Function overloads works:

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

type OF4 = EqEqEq<{ (x: 0, y: null): void; (x: number, y: null): void }, { (x: number, y: null): void; (x: 0, y: null): void }> // false

But function type intersection does not work:

type OF2 = EqEqEq<F & G, G & F> // true

Can we re-open this or something? Because there isn't a way =(

https://github.com/microsoft/TypeScript/issues/37314#issuecomment-598459316

Seems like it's fixed in master, with TS 4.0 as the milestone.

So, this doesn't need to be re-opened, I suppose. I forgot to link to that comment sooner, my bad.

@jituanlin AFAIK it relies on conditional types being deferred when T is not known. Assignability of deferred conditional types relies on an internal isTypeIdenticalTo check, which is only true for two conditional types if:

  • Both conditional types have the same constraint
  • The true and false branches of both conditions are the same type

where can I find the infomations about the internal 'isTypeIdenticalTo' check? I can't find anything in the typescript official website....

@ldqUndefined I do not remember it well, but you may find it in the source code (or not, since TypeScript source code changed a lot).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgrieder picture bgrieder  路  3Comments

weswigham picture weswigham  路  3Comments

jbondc picture jbondc  路  3Comments

wmaurer picture wmaurer  路  3Comments

zhuravlikjb picture zhuravlikjb  路  3Comments