Skip to content

Commit 01cbb49

Browse files
test: LastOfUnion ensures all union members would be picked.
1 parent 0699dc0 commit 01cbb49

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

test-d/last-of-union.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {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.
55
type UnionType = {a: 0} | {b: 0} | {a?: 0} | {readonly a?: 0} | {readonly a: 0};
@@ -11,3 +11,50 @@ expectType<never>({} as LastOfUnion<never>);
1111

1212
expectType<true>({} as IsUnknown<LastOfUnion<unknown>>);
1313
expectType<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

Comments
 (0)