Skip to content

Commit 5ea6654

Browse files
author
Andy Brenneke
committed
Move IsEqual to be first in Exact comparison to short-circuit before distribution
1 parent 0fdc7d2 commit 5ea6654

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

source/exact.d.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,16 @@ onlyAcceptNameImproved(invalidInput); // Compilation error
5353
@category Utilities
5454
*/
5555
export type Exact<ParameterType, InputType> =
56-
// If the parameter is a primitive, return it as is immediately to avoid it being converted to a complex type
57-
ParameterType extends Primitive ? ParameterType
58-
// If the parameter is an unknown, return it as is immediately to avoid it being converted to a complex type
59-
: IsUnknown<ParameterType> extends true ? unknown
60-
// If the parameter is a Function, return it as is because this type is not capable of handling function, leave it to TypeScript
61-
: ParameterType extends Function ? ParameterType
62-
: IsEqual<ParameterType, InputType> extends true ? ParameterType
63-
// Convert union of array to array of union: A[] & B[] => (A & B)[]
64-
: ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
65-
// In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
66-
: ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
67-
: ExactObject<ParameterType, InputType>;
56+
// Before distributing, check if the two types are equal and if so, return the parameter type immediately
57+
IsEqual<ParameterType, InputType> extends true ? ParameterType
58+
// If the parameter is a primitive, return it as is immediately to avoid it being converted to a complex type
59+
: ParameterType extends Primitive ? ParameterType
60+
// If the parameter is an unknown, return it as is immediately to avoid it being converted to a complex type
61+
: IsUnknown<ParameterType> extends true ? unknown
62+
// If the parameter is a Function, return it as is because this type is not capable of handling function, leave it to TypeScript
63+
: ParameterType extends Function ? ParameterType
64+
// Convert union of array to array of union: A[] & B[] => (A & B)[]
65+
: ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
66+
// In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
67+
: ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
68+
: ExactObject<ParameterType, InputType>;

test-d/exact.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,3 +537,15 @@ import type {Exact, Opaque} from '../index';
537537
// @ts-expect-error
538538
function_(withExcessSurname);
539539
}
540+
541+
// Spec - recursive type with union
542+
// @see TODO
543+
{
544+
type A = { a: A };
545+
type B = { b: string };
546+
type Expected = A | B;
547+
548+
const function_ = <T extends Exact<Expected, T>>(arguments_: T) => arguments_;
549+
550+
function_({} as Expected);
551+
}

0 commit comments

Comments
 (0)