forked from sindresorhus/type-fest
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexclude-exactly.d.ts
More file actions
124 lines (107 loc) · 3.59 KB
/
exclude-exactly.d.ts
File metadata and controls
124 lines (107 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import type {IsUnknown} from './is-unknown.d.ts';
import type {IsNever} from './is-never.d.ts';
import type {IsAny} from './is-any.d.ts';
import type {LastOfUnion} from './last-of-union.d.ts';
/**
Return `never` if the first and second arguments are identical.
Return the first argument if not.
(But there's a limitation about union/intersection type. See `IsEqual` in `source/is-equal.d.ts`.)
@example
```
type A = MatchOrNever<string | number, string>;
//=> string | number
type B = MatchOrNever<string | number, string | number>;
//=> never
type C = MatchOrNever<string | number, unknown>;
//=> string | number
type D = MatchOrNever<string, string | number>;
//=> string
```
This does NOT depend on assignability.
@example
```
type RO_0 = MatchOrNever<{readonly a: 0}, {a: 0}>;
//=> {readonly a: 0}
type RO_1 = MatchOrNever<{a: 0}, {readonly a: 0}>;
//=> {a: 0}
```
`unknown` and `never` cases, which easily break equality in type-level codebase.
@example
```
type E = MatchOrNever<unknown, never>;
//=> unknown
type F = MatchOrNever<unknown, unknown>;
//=> never
type G = MatchOrNever<never, never>;
//=> never
type H = MatchOrNever<never, unknown>;
//=> never
```
Note that this doesn't regard the identical union/intersection type `T | T` and/or `T & T` as `T` recursively.
e.g., `{a: 0} | {a: 0}` and/or `{a: 0} & {a: 0}` as `{a: 0}`.
@example
```
type IDUnion = MatchOrNever<{a: {b: 0}} | {a: {b: 0}}, {a: {b: 0}}>;
//=> never
type A = {a: {b: 0} | {b: 0}};
type RecurivelyIDUnion = MatchOrNever<A, {a: {b: 0}}>;
//=> A
```
*/
type MatchOrNever<A, B> =
[unknown, B] extends [A, never]
? A
// This equality code base below doesn't work if `A` is `unknown` and `B` is `never` case.
// So this branch should be wrapped to take care of this.
: (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2)
? never
: A;
/**
A stricter version of `Exclude<T, U>` that ensures objects with different key modifiers are not considered identical.
TypeScript's built-in `Exclude` and `ExcludeStrict` in `type-fest` don't distinguish key modifiers of objects.
@example
```
import type {ExcludeStrict} from 'type-fest';
type NeverReturned_0 = Exclude<{a: 0} | {readonly a: 0}, {readonly a: 0}>;
//=> never
type NeverReturned_1 = ExcludeStrict<{a: 0} | {readonly a: 0}, {readonly a: 0}>;
//=> never
```
`ExcludeExactly` keeps the union members element if the members are not identical.
@example
```
import type {ExcludeExactly} from 'type-fest';
type ExcludeNever = ExcludeExactly<{a: 0} | {a: 0} | {readonly a: 0}, never>;
//=> {a: 0} | {a: 0} | {readonly a: 0}
type ExcludeReadonlyKey = ExcludeExactly<{a: 0} | {readonly a: 0}, {readonly a: 0}>;
//=> {a: 0}
type ExcludeKey = ExcludeExactly<{readonly a: 0}, {a: 0}>;
//=> {readonly a: 0}
type ExcludeReadonly = ExcludeExactly<{readonly a: 0}, {readonly a: 0}>;
//=> never
type ExcludeSubType = ExcludeExactly<0 | 1 | number, 1>;
//=> number
type ExcludeAllSet = ExcludeExactly<0 | 1 | number, number>;
//=> never
type ExcludeFromUnknown = ExcludeExactly<unknown, string>;
//=> unknown
type ExcludeFromUnknownArray = ExcludeExactly<number[] | unknown[], number[]>;
//=> unknown[]
```
@category Improved Built-in
*/
export type ExcludeExactly<UnionU, DeleteT> =
LastOfUnion<DeleteT> extends infer D
? true extends IsNever<D>
? UnionU
: ExcludeExactly<_ExcludeExactly<UnionU, D>, _ExcludeExactly<DeleteT, D>>
: never;
type _ExcludeExactly<UnionU, DeleteT> =
true extends IsAny<DeleteT>
? never
: true extends IsUnknown<DeleteT>
? never
: UnionU extends unknown // Only for union distribution.
? MatchOrNever<UnionU, DeleteT>
: never;
export {};