11import { expectType } from 'tsd' ;
2- import type { LastOfUnion , IsAny , IsUnknown } from '../index.d.ts' ;
2+ import type { LastOfUnion , IsAny , IsUnknown , IsNever } from '../index.d.ts' ;
33
44// `LastOfUnion` distinguishes between different modifiers.
55type UnionType = { a : 0 } | { b : 0 } | { a ?: 0 } | { readonly a ?: 0 } | { readonly a : 0 } ;
@@ -11,3 +11,50 @@ expectType<never>({} as LastOfUnion<never>);
1111
1212expectType < true > ( { } as IsUnknown < LastOfUnion < unknown > > ) ;
1313expectType < true > ( { } as IsAny < LastOfUnion < any > > ) ;
14+
15+ // Ensure a loop of `LastOfUnion` returns all elements.
16+ type UnionToTuple < T , L = LastOfUnion < T > > =
17+ IsNever < T > extends false
18+ ? [ ...UnionToTuple < ExcludeExactly < T , L > > , L ]
19+ : [ ] ;
20+
21+ type MatchOrNever < A , B > =
22+ [ unknown , B ] extends [ A , never ]
23+ ? A
24+ // This equality code base below doesn't work if `A` is `unknown` and `B` is `never` case.
25+ // So this branch should be wrapped to take care of this.
26+ : ( < G > ( ) => G extends A & G | G ? 1 : 2 ) extends ( < G > ( ) => G extends B & G | G ? 1 : 2 )
27+ ? never
28+ : A ;
29+
30+ type ExcludeExactly < UnionU , DeleteT > =
31+ LastOfUnion < DeleteT > extends infer D
32+ ? true extends IsNever < D >
33+ ? UnionU
34+ : ExcludeExactly < _ExcludeExactly < UnionU , D > , _ExcludeExactly < DeleteT , D > >
35+ : never ;
36+
37+ type _ExcludeExactly < UnionU , DeleteT > =
38+ true extends IsAny < DeleteT >
39+ ? never
40+ : true extends IsUnknown < DeleteT >
41+ ? never
42+ : UnionU extends unknown // Only for union distribution.
43+ ? MatchOrNever < UnionU , DeleteT >
44+ : never ;
45+
46+ type DifferentModifierUnion = { readonly a : 0 } | { a : 0 } ;
47+ expectType < DifferentModifierUnion > ( { } as UnionToTuple < DifferentModifierUnion > [ number ] ) ;
48+ expectType < 2 > ( { } as UnionToTuple < DifferentModifierUnion > [ 'length' ] ) ;
49+
50+ type ReversedDifferentModifierUnion = { a : 0 } | { readonly a : 0 } ;
51+ expectType < ReversedDifferentModifierUnion > ( { } as UnionToTuple < ReversedDifferentModifierUnion > [ number ] ) ;
52+ expectType < 2 > ( { } as UnionToTuple < ReversedDifferentModifierUnion > [ 'length' ] ) ;
53+
54+ type SuperTypeUnion = { a : 0 ; b : 0 } | { a : 0 } ;
55+ expectType < SuperTypeUnion > ( { } as UnionToTuple < SuperTypeUnion > [ number ] ) ;
56+ expectType < 2 > ( { } as UnionToTuple < SuperTypeUnion > [ 'length' ] ) ;
57+
58+ type ReversedSuperTypeUnion = { a : 0 } | { a : 0 ; b : 0 } ;
59+ expectType < ReversedSuperTypeUnion > ( { } as UnionToTuple < ReversedSuperTypeUnion > [ number ] ) ;
60+ expectType < 2 > ( { } as UnionToTuple < ReversedSuperTypeUnion > [ 'length' ] ) ;
0 commit comments