0
# Validation and Logic
1
2
Multi-value validation, logical operations, and specialized validation patterns including predicate testing, enum checking, and truthiness validation.
3
4
## Capabilities
5
6
### Multi-value Validation
7
8
Check multiple values against predicates for comprehensive validation.
9
10
```typescript { .api }
11
/**
12
* Check if all values pass the predicate
13
* @param predicate - Function to test each value
14
* @param values - Values to test
15
* @returns True if all values pass predicate
16
*/
17
function isAll(predicate: Predicate, ...values: unknown[]): boolean;
18
19
/**
20
* Check if any value passes any of the predicates
21
* @param predicate - Single predicate or array of predicates
22
* @param values - Values to test
23
* @returns True if any value passes any predicate
24
*/
25
function isAny(predicate: Predicate | Predicate[], ...values: unknown[]): boolean;
26
27
type Predicate = (value: unknown) => boolean;
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import is from '@sindresorhus/is';
34
35
// Test all values against single predicate
36
is.all(is.string, 'hello', 'world', 'test'); // => true
37
is.all(is.string, 'hello', 42, 'test'); // => false
38
is.all(is.number, 1, 2, 3, 4); // => true
39
40
// Test any value against single predicate
41
is.any(is.string, 42, true, 'hello'); // => true
42
is.any(is.string, 42, true, null); // => false
43
44
// Test any value against multiple predicates
45
is.any([is.string, is.number], {}, true, 'hello'); // => true (string matches)
46
is.any([is.boolean, is.number], 'hello', [], {}); // => false
47
48
// Practical usage
49
function validateUserData(name: unknown, age: unknown, email: unknown) {
50
if (!is.all(is.string, name, email)) {
51
throw new Error('Name and email must be strings');
52
}
53
54
if (!is.number(age)) {
55
throw new Error('Age must be a number');
56
}
57
58
return { name, age, email };
59
}
60
61
// Flexible validation
62
function hasValidId(data: unknown[]) {
63
// Accept either string or number IDs
64
return is.any([is.string, is.number], ...data);
65
}
66
```
67
68
### Truthiness and Falsiness
69
70
Check logical truthiness and falsiness of values.
71
72
```typescript { .api }
73
/**
74
* Check if value is truthy
75
* @param value - Value to check
76
* @returns True if value is truthy
77
*/
78
function isTruthy<T>(value: T | Falsy): value is T;
79
80
/**
81
* Check if value is falsy
82
* @param value - Value to check
83
* @returns True if value is falsy
84
*/
85
function isFalsy(value: unknown): value is Falsy;
86
87
type Falsy = false | 0 | 0n | '' | null | undefined;
88
```
89
90
**Usage Examples:**
91
92
```typescript
93
import is from '@sindresorhus/is';
94
95
// Truthy values
96
is.truthy('hello'); // => true
97
is.truthy(42); // => true
98
is.truthy([]); // => true (arrays are truthy)
99
is.truthy({}); // => true (objects are truthy)
100
101
// Falsy values
102
is.falsy(false); // => true
103
is.falsy(0); // => true
104
is.falsy(0n); // => true
105
is.falsy(''); // => true
106
is.falsy(null); // => true
107
is.falsy(undefined); // => true
108
109
is.falsy('0'); // => false (string '0' is truthy)
110
is.falsy([]); // => false (empty array is truthy)
111
112
// Type guard usage
113
function processValue<T>(value: T | null | undefined) {
114
if (is.truthy(value)) {
115
// value is now typed as T (non-falsy)
116
return value.toString();
117
}
118
return 'No value provided';
119
}
120
121
// Filtering arrays
122
const mixedArray = ['hello', '', 0, 'world', null, 42, false];
123
const truthyValues = mixedArray.filter(is.truthy);
124
console.log(truthyValues); // ['hello', 'world', 42]
125
126
const falsyValues = mixedArray.filter(is.falsy);
127
console.log(falsyValues); // ['', 0, null, false]
128
```
129
130
### Enum Case Validation
131
132
Check if a value is a member of a TypeScript enum.
133
134
```typescript { .api }
135
/**
136
* Check if value is a member of the given enum
137
* @param value - Value to check
138
* @param targetEnum - Enum to check against
139
* @returns True if value is enum member
140
*/
141
function isEnumCase<T = unknown>(value: unknown, targetEnum: T): value is T[keyof T];
142
```
143
144
**Usage Examples:**
145
146
```typescript
147
import is from '@sindresorhus/is';
148
149
enum Direction {
150
Up = 'up',
151
Down = 'down',
152
Left = 'left',
153
Right = 'right'
154
}
155
156
enum Status {
157
Pending = 0,
158
Approved = 1,
159
Rejected = 2
160
}
161
162
is.enumCase('up', Direction); // => true
163
is.enumCase('diagonal', Direction); // => false
164
is.enumCase(1, Status); // => true
165
is.enumCase(3, Status); // => false
166
167
// Type guard usage
168
function processDirection(input: unknown) {
169
if (is.enumCase(input, Direction)) {
170
// input is now typed as Direction
171
switch (input) {
172
case Direction.Up:
173
return 'Moving up';
174
case Direction.Down:
175
return 'Moving down';
176
case Direction.Left:
177
return 'Moving left';
178
case Direction.Right:
179
return 'Moving right';
180
}
181
}
182
throw new Error('Invalid direction');
183
}
184
185
// API response validation
186
function validateStatus(response: { status: unknown }) {
187
if (is.enumCase(response.status, Status)) {
188
return response.status; // Typed as Status
189
}
190
throw new Error('Invalid status in response');
191
}
192
```
193
194
### Direct Instance Checking
195
196
Check if an instance is a direct instance of a class (not inherited).
197
198
```typescript { .api }
199
/**
200
* Check if instance is direct instance of class (not inherited)
201
* @param instance - Instance to check
202
* @param class_ - Class constructor to check against
203
* @returns True if instance is direct instance
204
*/
205
function isDirectInstanceOf<T>(instance: unknown, class_: Class<T>): instance is T;
206
207
type Class<T, Arguments extends unknown[] = any[]> = Constructor<T, Arguments> & {prototype: T};
208
```
209
210
**Usage Examples:**
211
212
```typescript
213
import is from '@sindresorhus/is';
214
215
class Animal {
216
name: string;
217
constructor(name: string) {
218
this.name = name;
219
}
220
}
221
222
class Dog extends Animal {
223
breed: string;
224
constructor(name: string, breed: string) {
225
super(name);
226
this.breed = breed;
227
}
228
}
229
230
const animal = new Animal('Generic');
231
const dog = new Dog('Buddy', 'Golden Retriever');
232
233
// Direct instance checking
234
is.directInstanceOf(animal, Animal); // => true
235
is.directInstanceOf(dog, Animal); // => false (inherited, not direct)
236
is.directInstanceOf(dog, Dog); // => true
237
238
// Compare with regular instanceof
239
console.log(dog instanceof Animal); // => true (inheritance chain)
240
console.log(is.directInstanceOf(dog, Animal)); // => false (direct only)
241
242
// Type guard usage
243
function processAnimal(animal: unknown) {
244
if (is.directInstanceOf(animal, Animal)) {
245
// animal is typed as Animal (not subclass)
246
console.log('Processing base animal:', animal.name);
247
} else if (is.directInstanceOf(animal, Dog)) {
248
// animal is typed as Dog
249
console.log('Processing dog:', animal.name, animal.breed);
250
}
251
}
252
```
253
254
### Property Key Validation
255
256
Check if a value can be used as an object property key.
257
258
```typescript { .api }
259
/**
260
* Check if value can be used as object property key
261
* @param value - Value to check
262
* @returns True if value is valid property key
263
*/
264
function isPropertyKey(value: unknown): value is PropertyKey;
265
266
type PropertyKey = string | number | symbol;
267
```
268
269
**Usage Examples:**
270
271
```typescript
272
import is from '@sindresorhus/is';
273
274
is.propertyKey('key'); // => true
275
is.propertyKey(42); // => true
276
is.propertyKey(Symbol('key')); // => true
277
278
is.propertyKey({}); // => false
279
is.propertyKey(null); // => false
280
is.propertyKey(true); // => false
281
282
// Type guard usage
283
function safeObjectAccess(obj: Record<PropertyKey, unknown>, key: unknown) {
284
if (is.propertyKey(key)) {
285
// key is now typed as PropertyKey
286
return obj[key];
287
}
288
throw new Error('Invalid property key');
289
}
290
291
// Dynamic property setting
292
function setProperty(obj: object, key: unknown, value: unknown) {
293
if (is.propertyKey(key)) {
294
(obj as any)[key] = value;
295
return true;
296
}
297
return false;
298
}
299
300
// Object key filtering
301
function filterValidKeys(keys: unknown[]): PropertyKey[] {
302
return keys.filter(is.propertyKey);
303
}
304
```
305
306
## Usage Patterns
307
308
### Batch Validation
309
310
```typescript
311
import is from '@sindresorhus/is';
312
313
function validateBatch<T>(
314
values: unknown[],
315
predicate: (value: unknown) => value is T
316
): T[] {
317
if (!is.all(predicate, ...values)) {
318
throw new Error('All values must pass validation');
319
}
320
return values as T[];
321
}
322
323
// Usage
324
const stringArray = validateBatch(['a', 'b', 'c'], is.string);
325
const numberArray = validateBatch([1, 2, 3], is.number);
326
327
function validateMixedTypes(values: unknown[]) {
328
const hasStrings = is.any(is.string, ...values);
329
const hasNumbers = is.any(is.number, ...values);
330
331
return {
332
hasStrings,
333
hasNumbers,
334
isHomogeneous: is.all(is.string, ...values) || is.all(is.number, ...values)
335
};
336
}
337
```
338
339
### Configuration Validation
340
341
```typescript
342
import is from '@sindresorhus/is';
343
344
enum LogLevel {
345
Debug = 'debug',
346
Info = 'info',
347
Warn = 'warn',
348
Error = 'error'
349
}
350
351
interface Config {
352
host: string;
353
port: number;
354
logLevel: LogLevel;
355
features: string[];
356
}
357
358
function validateConfig(config: Record<string, unknown>): Config {
359
// Required string fields
360
if (!is.all(is.string, config.host)) {
361
throw new Error('Host must be a string');
362
}
363
364
// Port validation
365
if (!is.number(config.port) || config.port <= 0) {
366
throw new Error('Port must be a positive number');
367
}
368
369
// Enum validation
370
if (!is.enumCase(config.logLevel, LogLevel)) {
371
throw new Error('Invalid log level');
372
}
373
374
// Array validation
375
if (!is.array(config.features, is.string)) {
376
throw new Error('Features must be array of strings');
377
}
378
379
return config as Config;
380
}
381
```
382
383
### Type-safe Filtering
384
385
```typescript
386
import is from '@sindresorhus/is';
387
388
function partitionArray<T>(
389
array: unknown[],
390
predicate: (value: unknown) => value is T
391
): [T[], unknown[]] {
392
const matching: T[] = [];
393
const nonMatching: unknown[] = [];
394
395
for (const item of array) {
396
if (predicate(item)) {
397
matching.push(item);
398
} else {
399
nonMatching.push(item);
400
}
401
}
402
403
return [matching, nonMatching];
404
}
405
406
// Usage
407
const mixedData = ['hello', 42, true, 'world', null, 3.14];
408
const [strings, nonStrings] = partitionArray(mixedData, is.string);
409
const [numbers, nonNumbers] = partitionArray(nonStrings, is.number);
410
411
console.log('Strings:', strings); // ['hello', 'world']
412
console.log('Numbers:', numbers); // [42, 3.14]
413
```
414
415
### Flexible Type Checking
416
417
```typescript
418
import is from '@sindresorhus/is';
419
420
function acceptMultipleTypes(value: unknown): string {
421
if (is.any([is.string, is.number, is.boolean], value)) {
422
return String(value);
423
}
424
425
if (is.any([is.array, is.plainObject], value)) {
426
return JSON.stringify(value);
427
}
428
429
return 'Unknown type';
430
}
431
432
function requireAllFields(data: Record<string, unknown>, ...fields: string[]) {
433
const values = fields.map(field => data[field]);
434
435
if (!is.all(is.truthy, ...values)) {
436
throw new Error(`Missing required fields: ${fields.join(', ')}`);
437
}
438
439
return data;
440
}
441
```
442
443
## Notes
444
445
- `isAll()` requires all values to pass the predicate; fails fast on first failure
446
- `isAny()` with single predicate tests if any value passes; with array tests if any value passes any predicate
447
- `isTruthy()` and `isFalsy()` follow JavaScript truthiness rules exactly
448
- `isEnumCase()` works with both string and numeric enums
449
- `isDirectInstanceOf()` checks prototype chain directly, not inheritance
450
- `isPropertyKey()` validates JavaScript property key types (string, number, symbol)
451
- All validation methods work with TypeScript type guards for compile-time type narrowing
452
- Multi-value validation is efficient for batch operations and configuration validation