0
# Array & Tuple Types
1
2
Specialized types for working with arrays, tuples, and array-like structures with type safety. These utilities help you manipulate and constrain array types effectively.
3
4
## Capabilities
5
6
### AnyArray
7
8
Matches `Array<Type>` or `ReadonlyArray<Type>` where `Type` is `any` by default.
9
10
```typescript { .api }
11
type AnyArray<Type = any> = Array<Type> | ReadonlyArray<Type>;
12
```
13
14
**Usage Example:**
15
16
```typescript
17
import type { AnyArray } from "ts-essentials";
18
19
type StringArrays = AnyArray<string>; // Array<string> | ReadonlyArray<string>
20
21
function processArray<T>(arr: AnyArray<T>): T[] {
22
return Array.from(arr);
23
}
24
25
// Works with both mutable and readonly arrays
26
processArray([1, 2, 3]); // Array<number>
27
processArray(["a", "b"] as const); // readonly string[]
28
```
29
30
### ArrayOrSingle
31
32
Matches `Type` or `Type[]`, useful for APIs that accept either a single value or an array.
33
34
```typescript { .api }
35
type ArrayOrSingle<Type> = Type | Type[];
36
```
37
38
**Usage Example:**
39
40
```typescript
41
import type { ArrayOrSingle } from "ts-essentials";
42
43
function addTags(tags: ArrayOrSingle<string>): string[] {
44
return Array.isArray(tags) ? tags : [tags];
45
}
46
47
// Both calls are valid
48
addTags("javascript"); // Works with single string
49
addTags(["javascript", "typescript"]); // Works with array
50
51
// API design example
52
interface SearchOptions {
53
query: string;
54
categories: ArrayOrSingle<string>;
55
sort: ArrayOrSingle<"date" | "relevance">;
56
}
57
```
58
59
### ReadonlyArrayOrSingle
60
61
Matches `Type` or `readonly Type[]`, similar to `ArrayOrSingle` but with readonly constraint.
62
63
```typescript { .api }
64
type ReadonlyArrayOrSingle<Type> = Type | readonly Type[];
65
```
66
67
**Usage Example:**
68
69
```typescript
70
import type { ReadonlyArrayOrSingle } from "ts-essentials";
71
72
function processReadonlyData<T>(data: ReadonlyArrayOrSingle<T>): readonly T[] {
73
return Array.isArray(data) ? data : [data] as const;
74
}
75
76
// Usage with readonly arrays
77
const result = processReadonlyData(["a", "b"] as const);
78
// result is readonly string[]
79
```
80
81
### ElementOf
82
83
Constructs a type which equals to array element type for type `Type`.
84
85
```typescript { .api }
86
type ElementOf<Type> = Type extends ReadonlyArray<infer U> ? U : never;
87
```
88
89
**Usage Example:**
90
91
```typescript
92
import type { ElementOf } from "ts-essentials";
93
94
type StringArray = string[];
95
type ArrayElement = ElementOf<StringArray>; // string
96
97
type TupleArray = [number, string, boolean];
98
type TupleElement = ElementOf<TupleArray>; // number | string | boolean
99
100
// Useful for generic functions working with array elements
101
function processElements<T extends ReadonlyArray<any>>(
102
arr: T,
103
processor: (element: ElementOf<T>) => ElementOf<T>
104
): T {
105
return arr.map(processor) as T;
106
}
107
108
const numbers = [1, 2, 3];
109
const doubled = processElements(numbers, x => x * 2); // number[]
110
```
111
112
### Head
113
114
Constructs a type which equals to first element in type `Type`.
115
116
```typescript { .api }
117
type Head<Type extends ReadonlyArray<any>> = Type extends readonly [infer H, ...any[]] ? H : never;
118
```
119
120
**Usage Example:**
121
122
```typescript
123
import type { Head } from "ts-essentials";
124
125
type Tuple = [string, number, boolean];
126
type FirstElement = Head<Tuple>; // string
127
128
type EmptyTuple = [];
129
type EmptyHead = Head<EmptyTuple>; // never
130
131
// Runtime helper function
132
function getHead<T extends ReadonlyArray<any>>(arr: T): Head<T> | undefined {
133
return arr[0] as Head<T> | undefined;
134
}
135
136
const tuple = ["hello", 42, true] as const;
137
const head = getHead(tuple); // "hello"
138
```
139
140
### Tail
141
142
Constructs a type which equals to elements but first one in type `Type`.
143
144
```typescript { .api }
145
type Tail<Type extends ReadonlyArray<any>> = Type extends readonly [any, ...infer T] ? T : [];
146
```
147
148
**Usage Example:**
149
150
```typescript
151
import type { Tail } from "ts-essentials";
152
153
type Tuple = [string, number, boolean];
154
type RestElements = Tail<Tuple>; // [number, boolean]
155
156
type SingleTuple = [string];
157
type SingleTail = Tail<SingleTuple>; // []
158
159
// Runtime helper function
160
function getTail<T extends ReadonlyArray<any>>(arr: T): Tail<T> {
161
return arr.slice(1) as Tail<T>;
162
}
163
164
const tuple = ["hello", 42, true] as const;
165
const tail = getTail(tuple); // [42, true]
166
```
167
168
### NonEmptyArray
169
170
Matches array with at least one element of type `Type`.
171
172
```typescript { .api }
173
type NonEmptyArray<Type> = [Type, ...Type[]];
174
```
175
176
**Usage Example:**
177
178
```typescript
179
import type { NonEmptyArray } from "ts-essentials";
180
181
function processNonEmptyArray<T>(arr: NonEmptyArray<T>): T {
182
return arr[0]; // Safe to access first element
183
}
184
185
// Type-safe functions that require non-empty arrays
186
function findMax(numbers: NonEmptyArray<number>): number {
187
return Math.max(...numbers);
188
}
189
190
// This works
191
findMax([1, 2, 3]); // OK
192
193
// This would cause a compile error:
194
// findMax([]); // Error: Argument of type '[]' is not assignable
195
196
// Type guard for runtime checking
197
function isNonEmptyArray<T>(arr: T[]): arr is NonEmptyArray<T> {
198
return arr.length > 0;
199
}
200
201
function safeProcessArray<T>(arr: T[]): T | undefined {
202
if (isNonEmptyArray(arr)) {
203
return processNonEmptyArray(arr); // Type-safe!
204
}
205
return undefined;
206
}
207
```
208
209
### Tuple
210
211
Matches type constraint for tuple with elements of type `Type` (`any` by default).
212
213
```typescript { .api }
214
type Tuple<Type = any> = readonly Type[];
215
```
216
217
**Usage Example:**
218
219
```typescript
220
import type { Tuple } from "ts-essentials";
221
222
// Generic tuple constraint
223
function processTuple<T extends Tuple>(tuple: T): T {
224
return tuple;
225
}
226
227
// Works with any tuple
228
processTuple([1, 2, 3] as const);
229
processTuple(["a", "b"] as const);
230
231
// Typed tuple constraint
232
function processStringTuple<T extends Tuple<string>>(tuple: T): T {
233
return tuple;
234
}
235
236
processTuple(["hello", "world"] as const); // OK
237
// processTuple([1, 2] as const); // Error: not all elements are strings
238
```
239
240
## Advanced Usage
241
242
Combine array and tuple utilities for complex operations:
243
244
```typescript
245
import type {
246
NonEmptyArray,
247
Head,
248
Tail,
249
ElementOf,
250
ArrayOrSingle
251
} from "ts-essentials";
252
253
// Recursive tuple processing
254
type ProcessTuple<T extends ReadonlyArray<any>> = T extends NonEmptyArray<any>
255
? [ProcessElement<Head<T>>, ...ProcessTuple<Tail<T>>]
256
: [];
257
258
type ProcessElement<T> = T extends string ? `processed_${T}` : T;
259
260
type Example = ProcessTuple<["hello", "world", 42]>;
261
// Result: ["processed_hello", "processed_world", 42]
262
263
// Safe array operations
264
function safeArrayOperation<T extends ReadonlyArray<any>>(
265
arr: T
266
): {
267
first: Head<T> | undefined;
268
rest: Tail<T>;
269
elementType: ElementOf<T> | undefined
270
} {
271
return {
272
first: arr[0] as Head<T> | undefined,
273
rest: arr.slice(1) as Tail<T>,
274
elementType: arr[0] as ElementOf<T> | undefined
275
};
276
}
277
278
// Flexible input handling
279
function flexibleInput<T>(input: ArrayOrSingle<T>): NonEmptyArray<T> | never {
280
const arr = Array.isArray(input) ? input : [input];
281
if (arr.length === 0) {
282
throw new Error("Input cannot be empty");
283
}
284
return arr as NonEmptyArray<T>;
285
}
286
```
287
288
## Types
289
290
```typescript { .api }
291
type ReadonlyArray<T> = readonly T[];
292
type Array<T> = T[];
293
```