Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature request]type level equal operator #27024

Closed
kgtkr opened this issue Sep 11, 2018 · 8 comments
Labels

Comments

@kgtkr
Copy link

@kgtkr kgtkr commented Sep 11, 2018

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:

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

This comment has been minimized.

Copy link

@AlCalzone AlCalzone commented Sep 11, 2018

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.

@kgtkr

This comment has been minimized.

Copy link
Author

@kgtkr kgtkr commented Sep 11, 2018

@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
@DanielRosenwasser

This comment has been minimized.

Copy link
Member

@DanielRosenwasser DanielRosenwasser commented Sep 11, 2018

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

@mattmccutchen

This comment has been minimized.

Copy link
Contributor

@mattmccutchen mattmccutchen commented Sep 15, 2018

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.)

@kgtkr

This comment has been minimized.

Copy link
Author

@kgtkr kgtkr commented Sep 22, 2018

Thank you
There was a way

@aleclarson

This comment has been minimized.

Copy link

@aleclarson aleclarson commented Apr 11, 2019

The best solution I have to date: spec.ts

Examples

@jituanlin

This comment has been minimized.

Copy link

@jituanlin jituanlin commented Jul 9, 2019

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.

@fatcerberus

This comment has been minimized.

Copy link

@fatcerberus fatcerberus commented Jul 12, 2019

@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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.