From d95e3382266f65313d0a01452272fb0ce851ae18 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sat, 13 Jul 2024 21:43:38 -0500 Subject: [PATCH 1/2] expose `ArrayElement` --- index.d.ts | 1 + readme.md | 1 + source/array-element.d.ts | 25 +++++++++++++++++++++++++ source/exact.d.ts | 3 ++- source/internal.d.ts | 9 --------- test-d/array-element.ts | 14 ++++++++++++++ 6 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 source/array-element.d.ts create mode 100644 test-d/array-element.ts diff --git a/index.d.ts b/index.d.ts index 7d3ec213d..c15322e61 100644 --- a/index.d.ts +++ b/index.d.ts @@ -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'; diff --git a/readme.md b/readme.md index f4b1164cb..5fd21cace 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/source/array-element.d.ts b/source/array-element.d.ts new file mode 100644 index 000000000..46db0c7d9 --- /dev/null +++ b/source/array-element.d.ts @@ -0,0 +1,25 @@ +/** +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: (array: T[]) => ArrayElement; + +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[0] : never; diff --git a/source/exact.d.ts b/source/exact.d.ts index a6c5686b4..2e1203e20 100644 --- a/source/exact.d.ts +++ b/source/exact.d.ts @@ -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'; diff --git a/source/internal.d.ts b/source/internal.d.ts index f98dfa7a5..e35ee4a5a 100644 --- a/source/internal.d.ts +++ b/source/internal.d.ts @@ -277,15 +277,6 @@ Extracts the type of an array or tuple minus the first element. */ export type ArrayTail = 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 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. diff --git a/test-d/array-element.ts b/test-d/array-element.ts new file mode 100644 index 000000000..516ae1ea0 --- /dev/null +++ b/test-d/array-element.ts @@ -0,0 +1,14 @@ +import {expectType} from 'tsd'; +import type {ArrayElement} from '../index'; + +declare const getArrayElement: (array: T) => ArrayElement; + +expectType(getArrayElement(['a', 'b', 'c'])); +expectType<'a'>(getArrayElement(['a', 'b', 'c'] as const)); +expectType(getArrayElement([1, 2, 3])); +expectType(getArrayElement(['a', 1])); + +declare const notArray: ArrayElement; + +expectType(getArrayElement([])); +expectType(notArray); From 98f307df592ba0077122a40060f74b16a3e73111 Mon Sep 17 00:00:00 2001 From: tommy-mitchell Date: Sat, 13 Jul 2024 21:45:06 -0500 Subject: [PATCH 2/2] try suggestion --- source/array-element.d.ts | 5 ++++- test-d/array-element.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/array-element.d.ts b/source/array-element.d.ts index 46db0c7d9..53a30a134 100644 --- a/source/array-element.d.ts +++ b/source/array-element.d.ts @@ -22,4 +22,7 @@ getMostCommonElement(['foo', 'bar', 'baz'] as const); @category Array */ -export type ArrayElement = ArrayType extends readonly unknown[] ? ArrayType[0] : never; +export type ArrayElement = + ArrayType extends ReadonlyArray + ? ElementType + : never; diff --git a/test-d/array-element.ts b/test-d/array-element.ts index 516ae1ea0..9f967f2cc 100644 --- a/test-d/array-element.ts +++ b/test-d/array-element.ts @@ -4,7 +4,7 @@ import type {ArrayElement} from '../index'; declare const getArrayElement: (array: T) => ArrayElement; expectType(getArrayElement(['a', 'b', 'c'])); -expectType<'a'>(getArrayElement(['a', 'b', 'c'] as const)); +expectType<'a' | 'b' | 'c'>(getArrayElement(['a', 'b', 'c'] as const)); expectType(getArrayElement([1, 2, 3])); expectType(getArrayElement(['a', 1]));