Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose ArrayElement type #914

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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 @@ -122,6 +122,7 @@ export type {ArrayIndices} from './source/array-indices';
export type {ArrayValues} from './source/array-values';
export type {ArraySlice} from './source/array-slice';
export type {ArraySplice} from './source/array-splice';
export type {ArrayElement} from './source/array-element';
export type {SetFieldType} from './source/set-field-type';
export type {Paths} from './source/paths';
export type {SharedUnionFieldsDeep} from './source/shared-union-fields-deep';
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ Click the type names for complete docs.
- [`ArrayIndices`](source/array-indices.d.ts) - Provides valid indices for a constant array or tuple.
- [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple.
- [`ArraySplice`](source/array-splice.d.ts) - Creates a new array type by adding or removing elements at a specified index range in the original array.
- [`ArrayElement`](source/array-element.d.ts) - Extracts the element type of an array or union of arrays.
- [`SetFieldType`](source/set-field-type.d.ts) - Create a type that changes the type of the given keys.
- [`Paths`](source/paths.d.ts) - Generate a union of all possible paths to properties in the given object.
- [`SharedUnionFieldsDeep`](source/shared-union-fields-deep.d.ts) - Create a type with shared fields from a union of object types, deeply traversing nested structures.
Expand Down
28 changes: 28 additions & 0 deletions source/array-element.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
Extracts the element type of an array or union of arrays.

Returns `never` if T is not an array.

It creates a type-safe way to access the element type of `unknown` type.

@example
```
import type {ArrayElement} from 'type-fest';

declare const getMostCommonElement: <T>(array: T[]) => ArrayElement<typeof array>;

getMostCommonElement([1, 2, 3]);
//=> 1 | 2 | 3

getMostCommonElement(['foo', 'bar', 'baz'] as const);
//=> 'foo' | 'bar' | 'baz'
```

@see {@link ArrayValues} for when you know that the input is an array.

@category Array
*/
export type ArrayElement<ArrayType extends readonly unknown[]> =
ArrayType extends ReadonlyArray<infer ElementType>
? ElementType
: never;
Comment on lines +25 to +28
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure this works @strongpauly

Should this be more?:

type ArrayElement<ArrayType extends readonly unknown[]> = 
  ArrayType extends readonly (infer ElementType)[] ? ElementType : never;

Copy paste from stackoverflow.com/questions/41253310/typescript-retrieve-element-type-information-from-array-type

// #906 (comment)

Choose a reason for hiding this comment

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

Well, as long as it returns a union of the types of the array elements, its fit for purpose, IMO.

3 changes: 2 additions & 1 deletion source/exact.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {ArrayElement, ObjectValue} from './internal';
import type {ObjectValue} from './internal';
import type {ArrayElement} from './array-element';
import type {IsEqual} from './is-equal';
import type {KeysOfUnion} from './keys-of-union';
import type {IsUnknown} from './is-unknown';
Expand Down Expand Up @@ -61,7 +62,7 @@
: ParameterType extends Function ? ParameterType
: IsEqual<ParameterType, InputType> extends true ? ParameterType
// Convert union of array to array of union: A[] & B[] => (A & B)[]
: ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.1.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript latest

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.2.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.3.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.4.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 16

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 20

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 65 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 18

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.
// In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
: ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.1.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript latest

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.2.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.3.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.4.0

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 16

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 20

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 67 in source/exact.d.ts

View workflow job for this annotation

GitHub Actions / Node.js 18

Type 'InputType' does not satisfy the constraint 'readonly unknown[]'.
: ExactObject<ParameterType, InputType>;
9 changes: 0 additions & 9 deletions source/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,6 @@ Extracts the type of an array or tuple minus the first element.
*/
export type ArrayTail<TArray extends UnknownArrayOrTuple> = TArray extends readonly [unknown, ...infer TTail] ? TTail : [];

/**
Extract the element of an array that also works for array union.

Returns `never` if T is not an array.

It creates a type-safe way to access the element type of `unknown` type.
*/
export type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;

/**
Extract the object field type if T is an object and K is a key of T, return `never` otherwise.

Expand Down
14 changes: 14 additions & 0 deletions test-d/array-element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {expectType} from 'tsd';
import type {ArrayElement} from '../index';

declare const getArrayElement: <T extends readonly unknown[]>(array: T) => ArrayElement<T>;

expectType<string>(getArrayElement(['a', 'b', 'c']));
expectType<'a' | 'b' | 'c'>(getArrayElement(['a', 'b', 'c'] as const));
expectType<number>(getArrayElement([1, 2, 3]));
expectType<string | number>(getArrayElement(['a', 1]));

declare const notArray: ArrayElement<unknown>;

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.1.0

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / TypeScript latest

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.2.0

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.3.0

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / TypeScript ~5.4.0

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / Node.js 16

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / Node.js 20

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

Check failure on line 11 in test-d/array-element.ts

View workflow job for this annotation

GitHub Actions / Node.js 18

Type 'unknown' does not satisfy the constraint 'readonly unknown[]'.

expectType<never>(getArrayElement([]));
expectType<never>(notArray);
Loading