diff --git a/ts/predicates/Equal.spec.ts b/ts/predicates/Equal.spec.ts index 878b3f7865..8927d6597e 100644 --- a/ts/predicates/Equal.spec.ts +++ b/ts/predicates/Equal.spec.ts @@ -1,6 +1,6 @@ import { assertType, Equal, NotEqual } from '../index.js' -describe('TypeEquals', () => { +describe('Equal', () => { test('match', () => { assertType.isTrue(true as Equal) }) @@ -54,9 +54,14 @@ describe('TypeEquals', () => { test('overlap is false', () => { assertType.isFalse(false as Equal<{ a: 1, b: 1 }, { a: 1, c: 2 }>) }) + + it('works with union types', () => { + assertType.isTrue(true as Equal<{ a: number, b: string }, { a: number } & { b: string }>) + assertType.isTrue(true as Equal<{ a: number, b?: string }, { a: number } & { b?: string }>) + }) }) -describe('TypeNotEquals', () => { +describe('NotEqual', () => { test('boolean', () => { assertType.isFalse(false as NotEqual) assertType.isFalse(false as NotEqual) @@ -68,4 +73,8 @@ describe('TypeNotEquals', () => { assertType.isTrue(true as NotEqual) assertType.isTrue(true as NotEqual) }) + it('works with union types', () => { + assertType.isFalse(false as NotEqual<{ a: number, b: string }, { a: number } & { b: string }>) + assertType.isTrue(true as NotEqual<{ a: number, b: string }, { a: number } & { b?: string }>) + }) }) diff --git a/ts/predicates/Equal.ts b/ts/predicates/Equal.ts index 1184350fc8..716fe9d9f4 100644 --- a/ts/predicates/Equal.ts +++ b/ts/predicates/Equal.ts @@ -1,14 +1,23 @@ -/** - * Checks if two types are equal. - * Borrow from `typepark`. - * The simple `A extends B ? B extends A ? true : false : false` - * does not work with boolean type. - */ -export type Equal = - (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) - ? Then : Else -export type IsEqual = Equal - -export type NotEqual = - (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? Else : Then -export type IsNotEqual = NotEqual +/** + * `() => T extends A ? 1 : 2` idea originate from `typepark` + * But it does not work with union types. + * + * `() => T extends A` is a trick to create an inferred type `T`. + * This is needed for `boolean`, `string`, and `number`, + * as they supports literal types. + */ + +/** + * Checks if two types are equal. + */ +export type Equal = + [A, B] extends [object, object] + ? (A extends B ? B extends A ? Then : Else : Else) + : (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? Then : Else +export type IsEqual = Equal + +export type NotEqual = + [A, B] extends [object, object] + ? (A extends B ? B extends A ? Else : Then : Then) + : (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? Else : Then +export type IsNotEqual = NotEqual