Add Xor type (#1254)

Co-authored-by: Som Shekhar Mukherjee <49264891+som-sm@users.noreply.github.com>
This commit is contained in:
benz 2025-10-08 18:36:41 +01:00 committed by GitHub
parent 1d89f154a7
commit ad04bc512e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 117 additions and 0 deletions

1
index.d.ts vendored
View File

@ -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';

View File

@ -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.

83
source/xor.d.ts vendored Normal file
View File

@ -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
test-d/xor.ts Normal file
View File

@ -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);