Skip to content

Commit 59bd056

Browse files
jericirenejsindresorhussom-sm
authored
Add ArrayLength type (#1344)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com> Co-authored-by: Som Shekhar Mukherjee <iamssmkhrj@gmail.com>
1 parent 35da6f7 commit 59bd056

File tree

5 files changed

+93
-7
lines changed

5 files changed

+93
-7
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export type {ArraySlice} from './source/array-slice.d.ts';
144144
export type {ArraySplice} from './source/array-splice.d.ts';
145145
export type {ArrayTail} from './source/array-tail.d.ts';
146146
export type {ArrayElement} from './source/array-element.d.ts';
147+
export type {ArrayLength} from './source/array-length.d.ts';
147148
export type {SetFieldType, SetFieldTypeOptions} from './source/set-field-type.d.ts';
148149
export type {Paths, PathsOptions} from './source/paths.d.ts';
149150
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
@@ -266,6 +266,7 @@ Click the type names for complete docs.
266266
- [`ExtractRestElement`](source/extract-rest-element.d.ts) - Extract the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element type from an array.
267267
- [`ExcludeRestElement`](source/exclude-rest-element.d.ts) - Create a tuple with the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element removed.
268268
- [`ArrayReverse`](source/array-reverse.d.ts) - Reverse the order of elements in a tuple type.
269+
- [`ArrayLength`](source/array-length.d.ts) - Return the length of an array. Equivalent to `T['length']` where `T` extends any array.
269270

270271
### Numeric
271272

source/array-length.d.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
Return the length of an array. Equivalent to `T['length']` where `T` extends any array.
3+
4+
Tuples resolve to numeric literals, while non-tuples resolve to the `number` type.
5+
6+
@example
7+
```
8+
import type {ArrayLength} from 'type-fest';
9+
10+
type TupleLength = ArrayLength<[1, 2, 3]>;
11+
//=> 3
12+
13+
type TupleWithOptionalMembersLength = ArrayLength<[1, 2, number?]>;
14+
//=> 2 | 3
15+
16+
type NonTupleArrayLength = ArrayLength<string[]>;
17+
//=> number
18+
19+
type TupleWithRestElementLength = ArrayLength<[1, 2, ...string[]]>;
20+
//=> number
21+
22+
// Distinguish between arrays with fixed and non-fixed lengths
23+
type IsFixedLengthArray<T extends readonly unknown[]> = number extends ArrayLength<T> ? false : true;
24+
25+
type A = IsFixedLengthArray<number[]>;
26+
//=> false
27+
28+
type B = IsFixedLengthArray<[1, 2, 3]>;
29+
//=> true
30+
```
31+
32+
@category Array
33+
*/
34+
export type ArrayLength<T extends readonly unknown[]> = T['length'];
35+
36+
export {};

source/internal/array.d.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ import type {OptionalKeysOf} from '../optional-keys-of.d.ts';
44
import type {UnknownArray} from '../unknown-array.d.ts';
55
import type {IsExactOptionalPropertyTypesEnabled, IfNotAnyOrNever} from './type.d.ts';
66

7-
/**
8-
Infer the length of the given array `<T>`.
9-
10-
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
11-
*/
12-
type ArrayLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
13-
147
/**
158
Matches any unknown array or tuple.
169
*/

test-d/array-length.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {expectType} from 'tsd';
2+
import type {ArrayLength, Primitive} from '../index.d.ts';
3+
4+
// Non-tuples
5+
expectType<number>({} as ArrayLength<unknown[]>);
6+
7+
// Tuples
8+
expectType<0>({} as ArrayLength<[]>);
9+
expectType<1>({} as ArrayLength<[never]>);
10+
expectType<3>({} as ArrayLength<['one', 2, true]>);
11+
expectType<2 | 3 | 4>({} as ArrayLength<[number, string, boolean?, boolean?]>);
12+
13+
expectType<number>({} as ArrayLength<[1, 2, ...unknown[]]>);
14+
expectType<number>({} as ArrayLength<[1, 2?, ...unknown[]]>);
15+
expectType<number>({} as ArrayLength<[...unknown[], 1, 2]>);
16+
expectType<number>({} as ArrayLength<[0, ...unknown[], 1, 2]>);
17+
18+
// Read-only arrays
19+
expectType<number>({} as ArrayLength<readonly unknown[]>);
20+
expectType<number>({} as ArrayLength<readonly never[]>);
21+
expectType<0>({} as ArrayLength<readonly []>);
22+
expectType<1>({} as ArrayLength<readonly [never]>);
23+
expectType<3>({} as ArrayLength<readonly ['one', 2, true]>);
24+
expectType<2 | 3 | 4>({} as ArrayLength<readonly [number, string, boolean?, boolean?]>);
25+
26+
expectType<number>({} as ArrayLength<readonly [1, 2, ...unknown[]]>);
27+
expectType<number>({} as ArrayLength<readonly [1, 2?, ...unknown[]]>);
28+
expectType<number>({} as ArrayLength<readonly [...unknown[], 1, 2]>);
29+
expectType<number>({} as ArrayLength<readonly [0, ...unknown[], 1, 2]>);
30+
31+
// Unions
32+
expectType<0 | 2>({} as ArrayLength<[] | [1, 2]>);
33+
expectType<0 | 2>({} as ArrayLength<readonly [] | readonly [1, 2]>);
34+
expectType<0 | 2>({} as ArrayLength<[] | readonly [1, 2]>);
35+
expectType<1 | 2 | 3 | 4>({} as ArrayLength<[1, 2?, 3?] | ['one', 'two', 'three', 'four']>);
36+
expectType<number>({} as ArrayLength<readonly [1] | [1, ...number[]]>);
37+
38+
// Edge cases and disallowed types
39+
expectType<never>({} as ArrayLength<never>);
40+
expectType<any>({} as ArrayLength<any>);
41+
42+
// @ts-expect-error
43+
type DisallowedPrimitive = ArrayLength<string>;
44+
// @ts-expect-error
45+
type DisallowedPrimitives = ArrayLength<Primitive>;
46+
// @ts-expect-error
47+
type DisallowedObject = ArrayLength<{}>;
48+
// @ts-expect-error
49+
type DisallowedMap = ArrayLength<Map<string, number>>;
50+
// @ts-expect-error
51+
type DisallowedSet = ArrayLength<Set<number>>;
52+
// @ts-expect-error
53+
type DisallowedRecord = ArrayLength<Record<string, unknown>>;
54+
// @ts-expect-error
55+
type DisallowedObjectWithLength = ArrayLength<{length: number}>;

0 commit comments

Comments
 (0)