Skip to content

Commit 2afaa40

Browse files
sindresorhussom-sm
andauthored
Add ArrayElement type (#1270)
Co-authored-by: Som Shekhar Mukherjee <49264891+som-sm@users.noreply.github.com>
1 parent cb977aa commit 2afaa40

File tree

6 files changed

+101
-10
lines changed

6 files changed

+101
-10
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export type {ArrayValues} from './source/array-values.d.ts';
141141
export type {ArraySlice} from './source/array-slice.d.ts';
142142
export type {ArraySplice} from './source/array-splice.d.ts';
143143
export type {ArrayTail} from './source/array-tail.d.ts';
144+
export type {ArrayElement} from './source/array-element.d.ts';
144145
export type {SetFieldType, SetFieldTypeOptions} from './source/set-field-type.d.ts';
145146
export type {Paths, PathsOptions} from './source/paths.d.ts';
146147
export type {AllUnionFields} from './source/all-union-fields.d.ts';

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ Click the type names for complete docs.
249249
- [`Includes`](source/includes.d.ts) - Returns a boolean for whether the given array includes the given item.
250250
- [`Join`](source/join.d.ts) - Join an array of strings and/or numbers using the given string as a delimiter.
251251
- [`ArraySlice`](source/array-slice.d.ts) - Returns an array slice of a given range, just like `Array#slice()`.
252+
- [`ArrayElement`](source/array-element.d.ts) - Extracts the element type of an array or tuple.
252253
- [`LastArrayElement`](source/last-array-element.d.ts) - Extract the type of the last element of an array.
253254
- [`FixedLengthArray`](source/fixed-length-array.d.ts) - Create a type that represents an array of the given type and length. The `Array` prototype methods that manipulate its length are excluded from the resulting type.
254255
- [`MultidimensionalArray`](source/multidimensional-array.d.ts) - Create a type that represents a multidimensional array of the given type and dimensions.

source/array-element.d.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type {UnknownArray} from './unknown-array.d.ts';
2+
3+
/**
4+
Extracts the element type of an array or tuple.
5+
6+
Use-cases:
7+
- When you need type-safe element extraction that returns `never` for non-arrays.
8+
- When extracting element types from generic array parameters in function signatures.
9+
- For better readability and explicit intent over using `T[number]` directly.
10+
11+
Note: Returns `never` if the type is not an array.
12+
13+
@example
14+
```
15+
import type {ArrayElement} from 'type-fest';
16+
17+
// Arrays
18+
type StringArray = ArrayElement<string[]>;
19+
//=> string
20+
21+
// Tuples
22+
type Tuple = ArrayElement<[1, 2, 3]>;
23+
//=> 1 | 2 | 3
24+
25+
// Type-safe
26+
type NotArray = ArrayElement<{a: string}>;
27+
//=> never
28+
29+
// Practical example
30+
declare function getRandomElement<T extends readonly unknown[]>(array: T): ArrayElement<T>;
31+
32+
getRandomElement(['foo', 'bar', 'baz'] as const);
33+
//=> 'foo' | 'bar' | 'baz'
34+
```
35+
36+
@see {@link ArrayValues} - For directly extracting values from a constant array type.
37+
@see {@link IterableElement} - For iterables like `Set`, `Map`, and generators (not suitable for all use cases due to different inference behavior).
38+
39+
@category Array
40+
*/
41+
export type ArrayElement<T> =
42+
T extends UnknownArray
43+
? T[number]
44+
: never;
45+
46+
export {};

source/exact.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type {ArrayElement, ObjectValue} from './internal/index.d.ts';
1+
import type {ObjectValue} from './internal/index.d.ts';
2+
import type {ArrayElement} from './array-element.d.ts';
23
import type {IsEqual} from './is-equal.d.ts';
34
import type {KeysOfUnion} from './keys-of-union.d.ts';
45
import type {IsUnknown} from './is-unknown.d.ts';

source/internal/array.d.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,6 @@ export type FirstArrayElement<TArray extends UnknownArrayOrTuple> = TArray exten
2424
? THead
2525
: never;
2626

27-
/**
28-
Extract the element of an array that also works for array union.
29-
30-
Returns `never` if T is not an array.
31-
32-
It creates a type-safe way to access the element type of `unknown` type.
33-
*/
34-
export type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
35-
3627
/**
3728
Returns the static, fixed-length portion of the given array, excluding variable-length parts.
3829

test-d/array-element.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {expectType} from 'tsd';
2+
import type {ArrayElement} from '../index.d.ts';
3+
4+
// Basic array
5+
expectType<string>({} as ArrayElement<string[]>);
6+
expectType<number>({} as ArrayElement<number[]>);
7+
8+
// Tuple
9+
expectType<1 | 2 | 3>({} as ArrayElement<[1, 2, 3]>);
10+
expectType<'a' | 'b' | 'c'>({} as ArrayElement<['a', 'b', 'c']>);
11+
12+
// Const tuple
13+
expectType<'foo' | 'bar' | 'baz'>({} as ArrayElement<readonly ['foo', 'bar', 'baz']>);
14+
expectType<1 | 2 | 3>({} as ArrayElement<readonly [1, 2, 3]>);
15+
16+
// Mixed types
17+
expectType<string | number>({} as ArrayElement<[string, number]>);
18+
expectType<string | number>({} as ArrayElement<[string, number]>);
19+
20+
// Readonly array
21+
expectType<string>({} as ArrayElement<readonly string[]>);
22+
expectType<1 | 2 | 3>({} as ArrayElement<readonly [1, 2, 3]>);
23+
24+
// Empty array
25+
expectType<never>({} as ArrayElement<[]>);
26+
expectType<never>({} as ArrayElement<readonly []>);
27+
28+
// Union of arrays
29+
expectType<1 | 2 | 3 | 4>({} as ArrayElement<[1, 2] | [3, 4]>);
30+
31+
// Function use case
32+
declare function getRandomElement<T extends readonly unknown[]>(array: T): ArrayElement<T>;
33+
34+
expectType<number>(getRandomElement([1, 2, 3]));
35+
expectType<'foo' | 'bar' | 'baz'>(getRandomElement(['foo', 'bar', 'baz'] as const));
36+
expectType<string>(getRandomElement(['foo', 'bar', 'baz']));
37+
38+
// Edge cases
39+
expectType<any>({} as ArrayElement<any>);
40+
expectType<never>({} as ArrayElement<never>);
41+
expectType<unknown>({} as ArrayElement<unknown[]>);
42+
43+
// Non-arrays return never
44+
expectType<never>({} as ArrayElement<string>);
45+
expectType<never>({} as ArrayElement<{a: string}>);
46+
47+
// Optional and rest elements
48+
expectType<1 | 2 | 3 | undefined>(1 as ArrayElement<[1, 2, 3?]>);
49+
expectType<string | number>(1 as ArrayElement<[string, ...number[]]>);
50+
expectType<1 | 2 | string>(1 as ArrayElement<[1, 2, ...string[]]>);
51+
expectType<1 | 2 | undefined | string>(1 as ArrayElement<[1, 2?, ...string[]]>);

0 commit comments

Comments
 (0)