Description
original issue: #27024
Search Terms
- Type System
- Equal
Suggestion
T1 == T2Use 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}// truefunction assertType<_T extends true>(){} assertType<Head<[1,2,3]> == 1>(); assertType<Head<[1,2,3]> == 2>();// Type ErrorChecklist
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)
workarounds
to summarize the discussion in #27024, the accepted solution was:
export type Equals<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
however there are many edge cases where it fails:
- doesn't work properly with overloads (function type intersections) - [Feature request]type level equal operator #27024 (comment)
- doesn't work properly with
{}
types - [Feature request]type level equal operator #27024 (comment) - doesn't work properly with
Equal<{ x: 1 } & { y: 2 }, { x: 1, y: 2 }>
- [Feature request]type level equal operator #27024 (comment)
there were some other workarounds posted that attempted to address these problems, but they also had cases where they didn't work properly.
what "equal" means
i think it's important for it to treat structurally equal types as equal. for example { a: string, b: number; }
should be considered equal to { a: string } & { b: number; }
as they behave exactly the same