Skip to content

Commit ad04bc5

Browse files
benzariasom-sm
andauthored
Add Xor type (#1254)
Co-authored-by: Som Shekhar Mukherjee <49264891+som-sm@users.noreply.github.com>
1 parent 1d89f15 commit ad04bc5

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export type {IfNull} from './source/if-null.d.ts';
148148
export type {IsUndefined} from './source/is-undefined.d.ts';
149149
export type {And} from './source/and.d.ts';
150150
export type {Or} from './source/or.d.ts';
151+
export type {Xor} from './source/xor.d.ts';
151152
export type {AllExtend, AllExtendOptions} from './source/all-extend.d.ts';
152153
export type {NonEmptyTuple} from './source/non-empty-tuple.d.ts';
153154
export type {FindGlobalInstanceType, FindGlobalType} from './source/find-global-type.d.ts';

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ Click the type names for complete docs.
180180
- [`DistributedPick`](source/distributed-pick.d.ts) - Picks keys from a type, distributing the operation over a union.
181181
- [`And`](source/and.d.ts) - Returns a boolean for whether two given types are both true.
182182
- [`Or`](source/or.d.ts) - Returns a boolean for whether either of two given types are true.
183+
- [`Xor`](source/xor.d.ts) - Returns a boolean for whether only one of two given types is true.
183184
- [`AllExtend`](source/all-extend.d.ts) - Returns a boolean for whether every element in an array type extends another type.
184185
- [`NonEmptyTuple`](source/non-empty-tuple.d.ts) - Matches any non-empty tuple.
185186
- [`NonEmptyString`](source/non-empty-string.d.ts) - Matches any non-empty string.

source/xor.d.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import type {Not} from './internal/type.d.ts';
2+
import type {And} from './and.d.ts';
3+
import type {Or} from './or.d.ts';
4+
5+
/**
6+
Returns a boolean for whether only one of two given types is true.
7+
8+
Use-case: Constructing complex conditional types where one single condition must be satisfied.
9+
10+
@example
11+
```
12+
import type {Xor} from 'type-fest';
13+
14+
type TT = Xor<true, true>;
15+
//=> false
16+
17+
type TF = Xor<true, false>;
18+
//=> true
19+
20+
type FT = Xor<false, true>;
21+
//=> true
22+
23+
type FF = Xor<false, false>;
24+
//=> false
25+
```
26+
27+
Note: When `boolean` is passed as an argument, it is distributed into separate cases, and the final result is a union of those cases.
28+
For example, `Xor<false, boolean>` expands to `Xor<false, true> | Xor<false, false>`, which simplifies to `true | false` (i.e., `boolean`).
29+
30+
@example
31+
```
32+
import type {Xor} from 'type-fest';
33+
34+
type A = Xor<false, boolean>;
35+
//=> boolean
36+
37+
type B = Xor<boolean, false>;
38+
//=> boolean
39+
40+
type C = Xor<true, boolean>;
41+
//=> boolean
42+
43+
type D = Xor<boolean, true>;
44+
//=> boolean
45+
46+
type E = Xor<boolean, boolean>;
47+
//=> boolean
48+
```
49+
50+
Note: If `never` is passed as an argument, it is treated as `false` and the result is computed accordingly.
51+
52+
@example
53+
```
54+
import type {Xor} from 'type-fest';
55+
56+
type A = Xor<true, never>;
57+
//=> true
58+
59+
type B = Xor<never, true>;
60+
//=> true
61+
62+
type C = Xor<false, never>;
63+
//=> false
64+
65+
type D = Xor<never, false>;
66+
//=> false
67+
68+
type E = Xor<boolean, never>;
69+
//=> boolean
70+
71+
type F = Xor<never, boolean>;
72+
//=> boolean
73+
74+
type G = Xor<never, never>;
75+
//=> false
76+
```
77+
78+
@see {@link And}
79+
@see {@link Or}
80+
*/
81+
export type Xor<A extends boolean, B extends boolean> = And<Or<A, B>, Not<And<A, B>>>;
82+
83+
export {};

test-d/xor.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {expectType} from 'tsd';
2+
import type {Xor} from '../source/xor.d.ts';
3+
4+
declare const boolean: boolean;
5+
6+
expectType<Xor<true, true>>(false);
7+
expectType<Xor<true, false>>(true);
8+
expectType<Xor<false, true>>(true);
9+
expectType<Xor<false, false>>(false);
10+
11+
expectType<Xor<true, boolean>>(boolean);
12+
expectType<Xor<boolean, true>>(boolean);
13+
expectType<Xor<false, boolean>>(boolean);
14+
expectType<Xor<boolean, false>>(boolean);
15+
expectType<Xor<boolean, boolean>>(boolean);
16+
17+
// Boundary cases
18+
expectType<Xor<true, any>>(boolean);
19+
expectType<Xor<any, true>>(boolean);
20+
expectType<Xor<false, any>>(boolean);
21+
expectType<Xor<any, false>>(boolean);
22+
expectType<Xor<boolean, any>>(boolean);
23+
expectType<Xor<any, boolean>>(boolean);
24+
expectType<Xor<any, any>>(boolean);
25+
26+
expectType<Xor<true, never>>(true);
27+
expectType<Xor<never, true>>(true);
28+
expectType<Xor<false, never>>(false);
29+
expectType<Xor<never, false>>(false);
30+
expectType<Xor<boolean, never>>(boolean);
31+
expectType<Xor<never, boolean>>(boolean);
32+
expectType<Xor<never, never>>(false);

0 commit comments

Comments
 (0)