0
# Assertions
1
2
Error-throwing assertion methods corresponding to all type checking functions, with optional custom error messages. Assertions provide runtime type validation that throws `TypeError` when checks fail.
3
4
## Capabilities
5
6
### Assertion Object
7
8
The `assert` object contains assertion methods for all type checking functions.
9
10
```typescript { .api }
11
/**
12
* Assertion methods that throw TypeError if type check fails
13
*/
14
const assert: Assert;
15
16
interface Assert {
17
// Basic type assertions
18
undefined: (value: unknown, message?: string) => asserts value is undefined;
19
string: (value: unknown, message?: string) => asserts value is string;
20
number: (value: unknown, message?: string) => asserts value is number;
21
boolean: (value: unknown, message?: string) => asserts value is boolean;
22
symbol: (value: unknown, message?: string) => asserts value is symbol;
23
bigint: (value: unknown, message?: string) => asserts value is bigint;
24
null: (value: unknown, message?: string) => asserts value is null;
25
26
// Object type assertions
27
array: <T = unknown>(value: unknown, assertion?: (element: unknown) => asserts element is T, message?: string) => asserts value is T[];
28
object: (value: unknown, message?: string) => asserts value is object;
29
function: (value: unknown, message?: string) => asserts value is Function;
30
date: (value: unknown, message?: string) => asserts value is Date;
31
regExp: (value: unknown, message?: string) => asserts value is RegExp;
32
33
// Multi-value assertions
34
all: (predicate: Predicate, ...values: unknown[]) => void | never;
35
any: (predicate: Predicate | Predicate[], ...values: unknown[]) => void | never;
36
}
37
38
type Predicate = (value: unknown) => boolean;
39
```
40
41
### Basic Type Assertions
42
43
Assert primitive and basic types with automatic error throwing.
44
45
**Usage Examples:**
46
47
```typescript
48
import { assert } from '@sindresorhus/is';
49
50
// Basic assertions
51
assert.string('hello'); // passes
52
assert.string(42); // throws TypeError
53
54
assert.number(42); // passes
55
assert.number('42'); // throws TypeError
56
57
// Custom error messages
58
assert.string(someValue, 'User name must be a string');
59
assert.number(config.port, 'Port must be a number');
60
61
// Type narrowing
62
function processUserInput(name: unknown, age: unknown) {
63
assert.string(name); // name is now typed as string
64
assert.number(age); // age is now typed as number
65
66
return {
67
name: name.toUpperCase(),
68
age: age + 1
69
};
70
}
71
```
72
73
### Array Assertions
74
75
Assert arrays with optional item validation.
76
77
```typescript { .api }
78
/**
79
* Assert value is array, optionally validating all items
80
* @param value - Value to assert
81
* @param assertion - Optional assertion for each array item
82
* @param message - Optional custom error message
83
*/
84
function assertArray<T = unknown>(
85
value: unknown,
86
assertion?: (element: unknown, message?: string) => asserts element is T,
87
message?: string
88
): asserts value is T[];
89
```
90
91
**Usage Examples:**
92
93
```typescript
94
import { assert } from '@sindresorhus/is';
95
96
// Basic array assertion
97
assert.array([1, 2, 3]); // passes
98
assert.array('not array'); // throws TypeError
99
100
// Array with item validation
101
assert.array([1, 2, 3], assert.number); // passes
102
assert.array([1, '2', 3], assert.number); // throws (string item)
103
104
// Type narrowing with validation
105
function processNumbers(data: unknown) {
106
assert.array(data, assert.number, 'Data must be array of numbers');
107
// data is now typed as number[]
108
109
return data.map(n => n * 2);
110
}
111
112
// Custom validation
113
function assertStringArray(value: unknown): asserts value is string[] {
114
assert.array(value, assert.string, 'Must be array of strings');
115
}
116
```
117
118
### Multi-value Assertions
119
120
Assert conditions across multiple values.
121
122
```typescript { .api }
123
/**
124
* Assert all values pass predicate
125
* @param predicate - Function to test each value
126
* @param values - Values to test
127
* @throws TypeError if any value fails
128
*/
129
function assertAll(predicate: Predicate, ...values: unknown[]): void | never;
130
131
/**
132
* Assert any value passes any predicate
133
* @param predicate - Single predicate or array of predicates
134
* @param values - Values to test
135
* @throws TypeError if no value passes any predicate
136
*/
137
function assertAny(predicate: Predicate | Predicate[], ...values: unknown[]): void | never;
138
```
139
140
**Usage Examples:**
141
142
```typescript
143
import { assert } from '@sindresorhus/is';
144
import is from '@sindresorhus/is';
145
146
// Assert all values match predicate
147
assert.all(is.string, 'hello', 'world'); // passes
148
assert.all(is.string, 'hello', 42); // throws
149
150
// Assert any value matches predicate
151
assert.any(is.string, 42, true, 'hello'); // passes (string found)
152
assert.any(is.string, 42, true, null); // throws (no strings)
153
154
// Multiple predicates
155
assert.any([is.string, is.number], 'hello', {}, []); // passes (string found)
156
157
// Function validation
158
function processUserData(name: unknown, email: unknown, phone: unknown) {
159
assert.all(is.string, name, email, phone);
160
// All are now typed as string
161
162
return {
163
name: name.trim(),
164
email: email.toLowerCase(),
165
phone: phone.replace(/\D/g, '')
166
};
167
}
168
169
function requireSomeContact(email: unknown, phone: unknown, address: unknown) {
170
assert.any(is.string, email, phone, address);
171
// At least one contact method is provided
172
}
173
```
174
175
## Usage Patterns
176
177
### API Input Validation
178
179
```typescript
180
import { assert } from '@sindresorhus/is';
181
import is from '@sindresorhus/is';
182
183
interface User {
184
id: number;
185
name: string;
186
email: string;
187
age: number;
188
isActive: boolean;
189
}
190
191
function createUser(data: unknown): User {
192
assert.object(data, 'User data must be an object');
193
194
const userData = data as Record<string, unknown>;
195
196
assert.number(userData.id, 'User ID must be a number');
197
assert.string(userData.name, 'Name must be a string');
198
assert.string(userData.email, 'Email must be a string');
199
assert.number(userData.age, 'Age must be a number');
200
assert.boolean(userData.isActive, 'isActive must be a boolean');
201
202
// Additional validation
203
if (!is.positiveNumber(userData.age)) {
204
throw new Error('Age must be positive');
205
}
206
207
if (!userData.email.includes('@')) {
208
throw new Error('Email must be valid');
209
}
210
211
return userData as User;
212
}
213
```
214
215
### Configuration Validation
216
217
```typescript
218
import { assert } from '@sindresorhus/is';
219
import is from '@sindresorhus/is';
220
221
interface DatabaseConfig {
222
host: string;
223
port: number;
224
database: string;
225
credentials: {
226
username: string;
227
password: string;
228
};
229
ssl: boolean;
230
poolSize: number;
231
}
232
233
function validateDatabaseConfig(config: unknown): DatabaseConfig {
234
assert.object(config, 'Database config must be an object');
235
236
const cfg = config as Record<string, unknown>;
237
238
// Basic type assertions
239
assert.string(cfg.host, 'Database host must be a string');
240
assert.number(cfg.port, 'Database port must be a number');
241
assert.string(cfg.database, 'Database name must be a string');
242
assert.boolean(cfg.ssl, 'SSL setting must be a boolean');
243
assert.number(cfg.poolSize, 'Pool size must be a number');
244
245
// Nested object validation
246
assert.object(cfg.credentials, 'Credentials must be an object');
247
const creds = cfg.credentials as Record<string, unknown>;
248
249
assert.all(is.string, creds.username, creds.password);
250
251
// Range validation
252
if (!is.inRange(cfg.port as number, [1, 65535])) {
253
throw new Error('Port must be between 1 and 65535');
254
}
255
256
if (!is.positiveNumber(cfg.poolSize as number)) {
257
throw new Error('Pool size must be positive');
258
}
259
260
return cfg as DatabaseConfig;
261
}
262
```
263
264
### Type-safe Data Processing
265
266
```typescript
267
import { assert } from '@sindresorhus/is';
268
import is from '@sindresorhus/is';
269
270
function processApiResponse(response: unknown) {
271
assert.object(response, 'API response must be an object');
272
273
const data = response as Record<string, unknown>;
274
275
assert.array(data.items, 'Response must contain items array');
276
277
// Process each item
278
const processedItems = (data.items as unknown[]).map((item, index) => {
279
assert.object(item, `Item ${index} must be an object`);
280
281
const itemData = item as Record<string, unknown>;
282
283
assert.string(itemData.id, `Item ${index} must have string ID`);
284
assert.string(itemData.name, `Item ${index} must have string name`);
285
286
// Optional fields
287
if (itemData.description !== undefined) {
288
assert.string(itemData.description, `Item ${index} description must be string`);
289
}
290
291
return {
292
id: itemData.id,
293
name: itemData.name,
294
description: itemData.description as string | undefined
295
};
296
});
297
298
return processedItems;
299
}
300
```
301
302
### Form Data Validation
303
304
```typescript
305
import { assert } from '@sindresorhus/is';
306
import is from '@sindresorhus/is';
307
308
interface ContactForm {
309
name: string;
310
email: string;
311
subject: string;
312
message: string;
313
subscribe: boolean;
314
}
315
316
function validateContactForm(formData: unknown): ContactForm {
317
assert.object(formData, 'Form data is required');
318
319
const data = formData as Record<string, unknown>;
320
321
// Required string fields
322
const requiredFields = ['name', 'email', 'subject', 'message'];
323
assert.all(is.string, ...requiredFields.map(field => data[field]));
324
325
// Additional validations
326
const form = data as Partial<ContactForm>;
327
328
if (!is.nonEmptyStringAndNotWhitespace(form.name)) {
329
throw new Error('Name cannot be empty');
330
}
331
332
if (!form.email?.includes('@')) {
333
throw new Error('Email must be valid');
334
}
335
336
if (!is.nonEmptyStringAndNotWhitespace(form.subject)) {
337
throw new Error('Subject is required');
338
}
339
340
if (!is.nonEmptyStringAndNotWhitespace(form.message)) {
341
throw new Error('Message is required');
342
}
343
344
// Optional boolean field
345
const subscribe = data.subscribe !== undefined ?
346
(assert.boolean(data.subscribe), data.subscribe) : false;
347
348
return {
349
name: form.name!,
350
email: form.email!,
351
subject: form.subject!,
352
message: form.message!,
353
subscribe
354
};
355
}
356
```
357
358
### Error Handling Patterns
359
360
```typescript
361
import { assert } from '@sindresorhus/is';
362
363
// Custom assertion wrapper
364
function assertWithContext<T>(
365
value: unknown,
366
assertion: (value: unknown, message?: string) => asserts value is T,
367
context: string
368
): asserts value is T {
369
try {
370
assertion(value);
371
} catch (error) {
372
throw new Error(`${context}: ${error.message}`);
373
}
374
}
375
376
// Usage
377
function processUser(userData: unknown, userId: string) {
378
assertWithContext(userData, assert.object, `User ${userId}`);
379
380
const user = userData as Record<string, unknown>;
381
382
assertWithContext(user.name, assert.string, `User ${userId} name`);
383
assertWithContext(user.age, assert.number, `User ${userId} age`);
384
}
385
386
// Batch validation with detailed errors
387
function validateBatch<T>(
388
items: unknown[],
389
assertion: (value: unknown, message?: string) => asserts value is T,
390
itemName: string
391
): T[] {
392
return items.map((item, index) => {
393
try {
394
assertion(item, `${itemName} at index ${index} is invalid`);
395
return item;
396
} catch (error) {
397
throw new Error(`Validation failed for ${itemName}[${index}]: ${error.message}`);
398
}
399
});
400
}
401
```
402
403
## Error Messages
404
405
### Default Error Messages
406
407
When assertions fail, they throw `TypeError` with descriptive messages:
408
409
```typescript
410
// Default error format
411
assert.string(42);
412
// TypeError: Expected value which is `string`, received value of type `number`.
413
414
assert.array('not array');
415
// TypeError: Expected value which is `Array`, received value of type `string`.
416
```
417
418
### Custom Error Messages
419
420
All assertion methods (except `assertAll` and `assertAny`) support custom error messages:
421
422
```typescript
423
import { assert } from '@sindresorhus/is';
424
425
assert.string(42, 'Username must be a string');
426
// TypeError: Username must be a string
427
428
assert.number(config.port, 'Configuration port must be a number');
429
// TypeError: Configuration port must be a number
430
431
assert.array(data, assert.string, 'Expected array of strings');
432
// TypeError: Expected array of strings
433
```
434
435
## Notes
436
437
- All assertion methods throw `TypeError` on failure, never return values
438
- Assertions provide TypeScript type narrowing after successful validation
439
- Custom error messages are recommended for user-facing validation
440
- `assertAll` and `assertAny` do not support custom messages
441
- Assertions are ideal for input validation, API boundaries, and configuration parsing
442
- Use assertions early in functions to establish type safety for the rest of the function
443
- Assertion failures should be caught and handled appropriately in production code