Skip to content
Open
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 @@ -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';
Expand Down
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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`.
Expand Down
50 changes: 50 additions & 0 deletions source/empty-array.d.ts
Original file line number Diff line number Diff line change
@@ -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<readonly []>; //=> true
type C = IsEmptyArray<[1, 2, 3]>; //=> false
type D = IsEmptyArray<string[]>; //=> false
```

@see {@link EmptyArray}
@category Array
*/
export type IsEmptyArray<T extends readonly unknown[]> =
[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 {};
54 changes: 54 additions & 0 deletions test-d/empty-array.ts
Original file line number Diff line number Diff line change
@@ -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<EmptyArray>([]);
expectAssignable<never[]>(emptyArray);

// Non-empty arrays should not be assignable
expectNotAssignable<EmptyArray>([1]);
expectNotAssignable<EmptyArray>([undefined]);
expectNotAssignable<EmptyArray>(['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<readonly never[]>(emptyArray);

// IsEmptyArray — Basic cases
expectType<IsEmptyArray<[]>>(true);
expectType<IsEmptyArray<never[]>>(true);
expectType<IsEmptyArray<readonly []>>(true);
expectType<IsEmptyArray<readonly never[]>>(true);

// IsEmptyArray — Non-empty cases
expectType<IsEmptyArray<[1]>>(false);
expectType<IsEmptyArray<[string, number]>>(false);
expectType<IsEmptyArray<readonly [1]>>(false);
expectType<IsEmptyArray<string[]>>(false);
expectType<IsEmptyArray<readonly string[]>>(false);

// IsEmptyArray — Edge cases
expectType<IsEmptyArray<any>>(false);
expectType<IsEmptyArray<never>>(false);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more tests:

Suggested change
expectType<IsEmptyArray<never>>(false);
expectType<IsEmptyArray<never>>(false);
// IsEmptyArray — Union behavior
expectType<IsEmptyArray<[] | [1]>>({} as boolean);
expectType<IsEmptyArray<readonly [] | readonly [1]>>({} as boolean);
// IsEmptyArray — More non-empty/array boundaries
expectType<IsEmptyArray<[never]>>(false);
expectType<IsEmptyArray<unknown[]>>(false);
expectType<IsEmptyArray<any[]>>(false);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also:

// @ts-expect-error
emptyArray.length = 1;


// IsEmptyArray — Union behavior
expectType<IsEmptyArray<[] | [1]>>({} as boolean);
expectType<IsEmptyArray<readonly [] | readonly [1]>>({} as boolean);

// IsEmptyArray — More non-empty/array boundaries
expectType<IsEmptyArray<[never]>>(false);
expectType<IsEmptyArray<unknown[]>>(false);
expectType<IsEmptyArray<any[]>>(false);