From e94dd86d1043dca5d5018f3f2cab97ec318b04c5 Mon Sep 17 00:00:00 2001 From: derodero24 Date: Sun, 8 Feb 2026 18:40:37 +0900 Subject: [PATCH] Add `EmptyArray` and `IsEmptyArray` types --- index.d.ts | 1 + readme.md | 2 ++ source/empty-array.d.ts | 50 ++++++++++++++++++++++++++++++++++++++ test-d/empty-array.ts | 54 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 source/empty-array.d.ts create mode 100644 test-d/empty-array.ts diff --git a/index.d.ts b/index.d.ts index 8a9926d8d..fb98f5529 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,6 +9,7 @@ export type * from './source/characters.d.ts'; export type {KeysOfUnion} from './source/keys-of-union.d.ts'; export type {DistributedOmit} from './source/distributed-omit.d.ts'; export type {DistributedPick} from './source/distributed-pick.d.ts'; +export type {EmptyArray, IsEmptyArray} from './source/empty-array.d.ts'; export type {EmptyObject, IsEmptyObject} from './source/empty-object.d.ts'; export type {IfEmptyObject} from './source/if-empty-object.d.ts'; export type {NonEmptyObject} from './source/non-empty-object.d.ts'; diff --git a/readme.md b/readme.md index 47e9fee30..11dcce310 100644 --- a/readme.md +++ b/readme.md @@ -184,6 +184,7 @@ Click the type names for complete docs. - [`Or`](source/or.d.ts) - Returns a boolean for whether either of two given types is 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. +- [`EmptyArray`](source/empty-array.d.ts) - Represents a strictly empty array, the `[]` value. - [`NonEmptyTuple`](source/non-empty-tuple.d.ts) - Matches any non-empty tuple. - [`NonEmptyString`](source/non-empty-string.d.ts) - Matches any non-empty string. - [`FindGlobalType`](source/find-global-type.d.ts) - Tries to find the type of a global with the given name. @@ -203,6 +204,7 @@ Click the type names for complete docs. - [`IsAny`](source/is-any.d.ts) - Returns a boolean for whether the given type is `any`. - [`IsNever`](source/is-never.d.ts) - Returns a boolean for whether the given type is `never`. - [`IsUnknown`](source/is-unknown.d.ts) - Returns a boolean for whether the given type is `unknown`. +- [`IsEmptyArray`](source/empty-array.d.ts) - Returns a boolean for whether the given array type is an empty array (`[]`). - [`IsEmptyObject`](source/empty-object.d.ts) - Returns a boolean for whether the type is strictly equal to an empty plain object, the `{}` value. - [`IsNull`](source/is-null.d.ts) - Returns a boolean for whether the given type is `null`. - [`IsUndefined`](source/is-undefined.d.ts) - Returns a boolean for whether the given type is `undefined`. diff --git a/source/empty-array.d.ts b/source/empty-array.d.ts new file mode 100644 index 000000000..0a97ce5b6 --- /dev/null +++ b/source/empty-array.d.ts @@ -0,0 +1,50 @@ +/** +Represents a strictly empty array, the `[]` value. + +Use-cases: +- Declaring a stable default value for an array parameter to avoid re-renders in React. +- Clearly expressing the intent of an empty array, similar to how {@link EmptyObject} is used for `{}`. + +@example +``` +import type {EmptyArray} from 'type-fest'; + +const defaultItems: EmptyArray = []; + +// Prevents accidental mutation +// @ts-expect-error +defaultItems.push(1); +``` + +@category Array +*/ +export type EmptyArray = []; + +/** +Returns a `boolean` for whether the given array type is an empty array (`[]`). + +@example +``` +import type {IsEmptyArray} from 'type-fest'; + +type A = IsEmptyArray<[]>; //=> true +type B = IsEmptyArray; //=> true +type C = IsEmptyArray<[1, 2, 3]>; //=> false +type D = IsEmptyArray; //=> false +``` + +@see {@link EmptyArray} +@category Array +*/ +export type IsEmptyArray = + [T] extends [never] + ? false + : T extends readonly [unknown, ...unknown[]] + ? false + : number extends T['length'] + ? [T[number]] extends [never] ? true : false + : T['length'] extends 0 + ? true + : false; + +export {}; diff --git a/test-d/empty-array.ts b/test-d/empty-array.ts new file mode 100644 index 000000000..7291c0bfa --- /dev/null +++ b/test-d/empty-array.ts @@ -0,0 +1,54 @@ +import {expectAssignable, expectNotAssignable, expectType} from 'tsd'; +import type {EmptyArray, IsEmptyArray} from '../index.d.ts'; + +// EmptyArray — Assignability +declare let emptyArray: EmptyArray; +expectAssignable([]); +expectAssignable(emptyArray); + +// Non-empty arrays should not be assignable +expectNotAssignable([1]); +expectNotAssignable([undefined]); +expectNotAssignable(['a', 'b']); + +// Non-array types should not be assignable +// @ts-expect-error +emptyArray = {}; +// @ts-expect-error +emptyArray = 42; +// @ts-expect-error +emptyArray = null; +// @ts-expect-error +emptyArray = 'string'; + +// @ts-expect-error +emptyArray.length = 1; + +// Readonly compatibility +expectAssignable(emptyArray); + +// IsEmptyArray — Basic cases +expectType>(true); +expectType>(true); +expectType>(true); +expectType>(true); + +// IsEmptyArray — Non-empty cases +expectType>(false); +expectType>(false); +expectType>(false); +expectType>(false); +expectType>(false); + +// IsEmptyArray — Edge cases +expectType>(false); +expectType>(false); + +// IsEmptyArray — Union behavior +expectType>({} as boolean); +expectType>({} as boolean); + +// IsEmptyArray — More non-empty/array boundaries +expectType>(false); +expectType>(false); +expectType>(false);