From ad04bc512e42335860fb3ee557de62c170f62ff0 Mon Sep 17 00:00:00 2001 From: benz Date: Wed, 8 Oct 2025 18:36:41 +0100 Subject: [PATCH] Add `Xor` type (#1254) Co-authored-by: Som Shekhar Mukherjee <49264891+som-sm@users.noreply.github.com> --- index.d.ts | 1 + readme.md | 1 + source/xor.d.ts | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ test-d/xor.ts | 32 +++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 source/xor.d.ts create mode 100644 test-d/xor.ts diff --git a/index.d.ts b/index.d.ts index b00eea7d..aa48c653 100644 --- a/index.d.ts +++ b/index.d.ts @@ -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'; diff --git a/readme.md b/readme.md index 82922263..c3006aff 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/source/xor.d.ts b/source/xor.d.ts new file mode 100644 index 00000000..2329ea62 --- /dev/null +++ b/source/xor.d.ts @@ -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; +//=> false + +type TF = Xor; +//=> true + +type FT = Xor; +//=> true + +type FF = Xor; +//=> 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` expands to `Xor | Xor`, which simplifies to `true | false` (i.e., `boolean`). + +@example +``` +import type {Xor} from 'type-fest'; + +type A = Xor; +//=> boolean + +type B = Xor; +//=> boolean + +type C = Xor; +//=> boolean + +type D = Xor; +//=> boolean + +type E = Xor; +//=> 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 + +type B = Xor; +//=> true + +type C = Xor; +//=> false + +type D = Xor; +//=> false + +type E = Xor; +//=> boolean + +type F = Xor; +//=> boolean + +type G = Xor; +//=> false +``` + +@see {@link And} +@see {@link Or} +*/ +export type Xor = And, Not>>; + +export {}; diff --git a/test-d/xor.ts b/test-d/xor.ts new file mode 100644 index 00000000..abb630af --- /dev/null +++ b/test-d/xor.ts @@ -0,0 +1,32 @@ +import {expectType} from 'tsd'; +import type {Xor} from '../source/xor.d.ts'; + +declare const boolean: boolean; + +expectType>(false); +expectType>(true); +expectType>(true); +expectType>(false); + +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); + +// Boundary cases +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); +expectType>(boolean); + +expectType>(true); +expectType>(true); +expectType>(false); +expectType>(false); +expectType>(boolean); +expectType>(boolean); +expectType>(false);