Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export type {IfNull} from './source/if-null.d.ts';
export type {IsUndefined} from './source/is-undefined.d.ts';
export type {And} from './source/and.d.ts';
export type {Or} from './source/or.d.ts';
export type {Xor} from './source/xor.d.ts';
export type {AllExtend, AllExtendOptions} from './source/all-extend.d.ts';
export type {NonEmptyTuple} from './source/non-empty-tuple.d.ts';
export type {FindGlobalInstanceType, FindGlobalType} from './source/find-global-type.d.ts';
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ Click the type names for complete docs.
- [`DistributedPick`](source/distributed-pick.d.ts) - Picks keys from a type, distributing the operation over a union.
- [`And`](source/and.d.ts) - Returns a boolean for whether two given types are both true.
- [`Or`](source/or.d.ts) - Returns a boolean for whether either of two given types are true.
- [`Xor`](source/xor.d.ts) - Returns a boolean for whether only one of two given types is true.
- [`AllExtend`](source/all-extend.d.ts) - Returns a boolean for whether every element in an array type extends another type.
- [`NonEmptyTuple`](source/non-empty-tuple.d.ts) - Matches any non-empty tuple.
- [`NonEmptyString`](source/non-empty-string.d.ts) - Matches any non-empty string.
Expand Down
83 changes: 83 additions & 0 deletions source/xor.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type {Not} from './internal/type.d.ts';
import type {And} from './and.d.ts';
import type {Or} from './or.d.ts';

/**
Returns a boolean for whether only one of two given types is true.

Use-case: Constructing complex conditional types where one single condition must be satisfied.

@example
```
import type {Xor} from 'type-fest';

type TT = Xor<true, true>;
//=> false

type TF = Xor<true, false>;
//=> true

type FT = Xor<false, true>;
//=> true

type FF = Xor<false, false>;
//=> false
```

Note: When `boolean` is passed as an argument, it is distributed into separate cases, and the final result is a union of those cases.
For example, `Xor<false, boolean>` expands to `Xor<false, true> | Xor<false, false>`, which simplifies to `true | false` (i.e., `boolean`).

@example
```
import type {Xor} from 'type-fest';

type A = Xor<false, boolean>;
//=> boolean

type B = Xor<boolean, false>;
//=> boolean

type C = Xor<true, boolean>;
//=> boolean

type D = Xor<boolean, true>;
//=> boolean

type E = Xor<boolean, boolean>;
//=> boolean
```

Note: If `never` is passed as an argument, it is treated as `false` and the result is computed accordingly.

@example
```
import type {Xor} from 'type-fest';

type A = Xor<true, never>;
//=> true

type B = Xor<never, true>;
//=> true

type C = Xor<false, never>;
//=> false

type D = Xor<never, false>;
//=> false

type E = Xor<boolean, never>;
//=> boolean

type F = Xor<never, boolean>;
//=> boolean

type G = Xor<never, never>;
//=> false
```

@see {@link And}
@see {@link Or}
*/
export type Xor<A extends boolean, B extends boolean> = And<Or<A, B>, Not<And<A, B>>>;

export {};
32 changes: 32 additions & 0 deletions test-d/xor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {expectType} from 'tsd';
import type {Xor} from '../source/xor.d.ts';

declare const boolean: boolean;

expectType<Xor<true, true>>(false);
expectType<Xor<true, false>>(true);
expectType<Xor<false, true>>(true);
expectType<Xor<false, false>>(false);

expectType<Xor<true, boolean>>(boolean);
expectType<Xor<boolean, true>>(boolean);
expectType<Xor<false, boolean>>(boolean);
expectType<Xor<boolean, false>>(boolean);
expectType<Xor<boolean, boolean>>(boolean);

// Boundary cases
expectType<Xor<true, any>>(boolean);
expectType<Xor<any, true>>(boolean);
expectType<Xor<false, any>>(boolean);
expectType<Xor<any, false>>(boolean);
expectType<Xor<boolean, any>>(boolean);
expectType<Xor<any, boolean>>(boolean);
expectType<Xor<any, any>>(boolean);

expectType<Xor<true, never>>(true);
expectType<Xor<never, true>>(true);
expectType<Xor<false, never>>(false);
expectType<Xor<never, false>>(false);
expectType<Xor<boolean, never>>(boolean);
expectType<Xor<never, boolean>>(boolean);
expectType<Xor<never, never>>(false);
Loading