0
# Type Aliases and Guards
1
2
Type aliases and guards provide common type definitions with corresponding runtime type guard functions for type checking at runtime. These utilities bridge compile-time type safety with runtime type validation.
3
4
## Import
5
6
```typescript
7
import {
8
// Type aliases
9
Primitive, Falsy, Falsey, Nullish,
10
11
// Type guard functions
12
isPrimitive, isFalsy, isNullish
13
} from 'utility-types';
14
```
15
16
For CommonJS:
17
18
```javascript
19
const {
20
// Type aliases
21
Primitive, Falsy, Falsey, Nullish,
22
23
// Type guard functions
24
isPrimitive, isFalsy, isNullish
25
} = require('utility-types');
26
```
27
28
## Type Aliases
29
30
### Primitive
31
32
Represents JavaScript primitive types: string, number, bigint, boolean, symbol, null, and undefined.
33
34
```typescript { .api }
35
type Primitive = string | number | bigint | boolean | symbol | null | undefined;
36
```
37
38
**Usage:**
39
40
```typescript
41
// Type checking
42
function isSimpleValue(value: unknown): value is Primitive {
43
return value !== Object(value);
44
}
45
46
// Excluding complex types
47
type SimpleData<T> = T extends Primitive ? T : never;
48
49
type Example1 = SimpleData<string>; // Result: string
50
type Example2 = SimpleData<object>; // Result: never
51
52
// Filtering object properties
53
interface MixedData {
54
id: number;
55
name: string;
56
settings: object;
57
callback: () => void;
58
isActive: boolean;
59
metadata: Record<string, any>;
60
}
61
62
type PrimitiveFields = {
63
[K in keyof MixedData]: MixedData[K] extends Primitive ? K : never;
64
}[keyof MixedData];
65
// Result: 'id' | 'name' | 'isActive'
66
67
type PrimitiveData = Pick<MixedData, PrimitiveFields>;
68
// Result: { id: number; name: string; isActive: boolean; }
69
70
// Practical usage in serialization
71
function serializePrimitives<T extends Record<string, any>>(obj: T): Pick<T, {
72
[K in keyof T]: T[K] extends Primitive ? K : never;
73
}[keyof T]> {
74
const result = {} as any;
75
for (const [key, value] of Object.entries(obj)) {
76
if (value !== Object(value)) {
77
result[key] = value;
78
}
79
}
80
return result;
81
}
82
```
83
84
### Falsy
85
86
Represents JavaScript falsy values: false, empty string, 0, null, and undefined.
87
88
```typescript { .api }
89
type Falsy = false | '' | 0 | null | undefined;
90
```
91
92
**Usage:**
93
94
```typescript
95
// Remove falsy values from union types
96
type TruthyString = Exclude<string, Falsy>;
97
// Result: string (but excludes empty string)
98
99
type TruthyNumber = Exclude<number, Falsy>;
100
// Result: number (but excludes 0)
101
102
// Filter arrays to remove falsy values
103
function filterTruthy<T>(array: T[]): Array<Exclude<T, Falsy>> {
104
return array.filter(Boolean) as Array<Exclude<T, Falsy>>;
105
}
106
107
const mixed = [1, 0, 'hello', '', true, false, null, undefined];
108
const truthy = filterTruthy(mixed);
109
// Type: Array<1 | 'hello' | true>
110
// Value: [1, 'hello', true]
111
112
// Conditional type based on falsy check
113
type IsTruthy<T> = T extends Falsy ? false : true;
114
115
type Test1 = IsTruthy<0>; // Result: false
116
type Test2 = IsTruthy<42>; // Result: true
117
type Test3 = IsTruthy<''>; // Result: false
118
type Test4 = IsTruthy<'hello'>; // Result: true
119
120
// Default value patterns
121
function withDefault<T>(value: T | Falsy, defaultValue: T): T {
122
return value || defaultValue;
123
}
124
125
const result1 = withDefault('', 'default'); // Result: 'default'
126
const result2 = withDefault('value', 'default'); // Result: 'value'
127
```
128
129
### Falsey (Deprecated)
130
131
Deprecated alias for `Falsy`. Provided for backward compatibility until v4.
132
133
```typescript { .api }
134
type Falsey = Falsy;
135
```
136
137
**Usage:**
138
139
```typescript
140
// Deprecated - use Falsy instead
141
type OldFalseyType = Falsey;
142
143
// Preferred
144
type NewFalsyType = Falsy;
145
146
// Migration guide
147
function migrationExample(value: unknown): value is Falsy {
148
// Old: value is Falsey
149
// New: value is Falsy
150
return !value;
151
}
152
```
153
154
### Nullish
155
156
Represents nullish values in TypeScript: null and undefined.
157
158
```typescript { .api }
159
type Nullish = null | undefined;
160
```
161
162
**Usage:**
163
164
```typescript
165
// Nullish coalescing patterns
166
function withNullishDefault<T>(value: T | Nullish, defaultValue: T): T {
167
return value ?? defaultValue;
168
}
169
170
const result1 = withNullishDefault(null, 'default'); // Result: 'default'
171
const result2 = withNullishDefault(undefined, 'default'); // Result: 'default'
172
const result3 = withNullishDefault('', 'default'); // Result: '' (empty string is not nullish)
173
const result4 = withNullishDefault(0, 42); // Result: 0 (zero is not nullish)
174
175
// Remove nullish values from union types
176
type NonNullishString = Exclude<string | null | undefined, Nullish>;
177
// Result: string
178
179
// Optional property handling
180
interface Config {
181
host?: string;
182
port?: number;
183
timeout?: number;
184
}
185
186
type RequiredConfig = {
187
[K in keyof Config]-?: Exclude<Config[K], Nullish>;
188
};
189
// Result: { host: string; port: number; timeout: number; }
190
191
// Array filtering
192
function filterNullish<T>(array: Array<T | Nullish>): T[] {
193
return array.filter((item): item is T => item != null);
194
}
195
196
const withNulls = [1, null, 2, undefined, 3];
197
const withoutNulls = filterNullish(withNulls);
198
// Type: number[]
199
// Value: [1, 2, 3]
200
201
// Conditional types
202
type IsNullish<T> = T extends Nullish ? true : false;
203
204
type Test1 = IsNullish<null>; // Result: true
205
type Test2 = IsNullish<undefined>; // Result: true
206
type Test3 = IsNullish<0>; // Result: false
207
type Test4 = IsNullish<''>; // Result: false
208
```
209
210
## Type Guard Functions
211
212
### isPrimitive
213
214
Runtime type guard to check if a value is a primitive type.
215
216
```typescript { .api }
217
function isPrimitive(val: unknown): val is Primitive;
218
```
219
220
**Usage:**
221
222
```typescript
223
// Basic usage
224
const value1: unknown = 'hello';
225
const value2: unknown = { name: 'John' };
226
const value3: unknown = [1, 2, 3];
227
228
if (isPrimitive(value1)) {
229
// value1 is now typed as Primitive
230
console.log(typeof value1); // Safe to use
231
}
232
233
if (isPrimitive(value2)) {
234
// This block won't execute - objects are not primitive
235
} else {
236
// value2 is unknown but we know it's not primitive
237
console.log('Complex type');
238
}
239
240
// Filtering arrays
241
const mixedArray: unknown[] = [1, 'hello', {}, [], true, null, undefined, Symbol('test')];
242
243
const primitives = mixedArray.filter(isPrimitive);
244
// Type: Primitive[]
245
// Contains: [1, 'hello', true, null, undefined, Symbol('test')]
246
247
const nonPrimitives = mixedArray.filter(item => !isPrimitive(item));
248
// Type: unknown[] (but we know they're not primitive)
249
// Contains: [{}, []]
250
251
// Type-safe serialization
252
function safeSerialization(data: Record<string, unknown>): Record<string, Primitive> {
253
const result: Record<string, Primitive> = {};
254
255
for (const [key, value] of Object.entries(data)) {
256
if (isPrimitive(value)) {
257
result[key] = value; // Type-safe assignment
258
}
259
}
260
261
return result;
262
}
263
264
// Form data processing
265
function processFormData(formData: Record<string, unknown>) {
266
const primitiveData: Record<string, Primitive> = {};
267
const complexData: Record<string, unknown> = {};
268
269
for (const [key, value] of Object.entries(formData)) {
270
if (isPrimitive(value)) {
271
primitiveData[key] = value;
272
} else {
273
complexData[key] = value;
274
}
275
}
276
277
return { primitiveData, complexData };
278
}
279
```
280
281
### isFalsy
282
283
Runtime type guard to check if a value is falsy.
284
285
```typescript { .api }
286
function isFalsy(val: unknown): val is Falsy;
287
```
288
289
**Usage:**
290
291
```typescript
292
// Basic usage
293
const values = [0, '', false, null, undefined, 'hello', 1, true, {}];
294
295
const falsyValues = values.filter(isFalsy);
296
// Type: Falsy[]
297
// Contains: [0, '', false, null, undefined]
298
299
const truthyValues = values.filter(val => !isFalsy(val));
300
// Type: unknown[] (but we know they're truthy)
301
// Contains: ['hello', 1, true, {}]
302
303
// Form validation
304
function validateFormField(value: unknown): string | null {
305
if (isFalsy(value)) {
306
return 'Field is required';
307
}
308
309
// value is now typed as Exclude<unknown, Falsy>
310
// We know it's not falsy
311
return null;
312
}
313
314
// Array compaction
315
function compact<T>(array: T[]): Array<Exclude<T, Falsy>> {
316
return array.filter((item): item is Exclude<T, Falsy> => !isFalsy(item));
317
}
318
319
const messyArray = [1, 0, 'test', '', true, false, null, undefined, 'hello'];
320
const cleanArray = compact(messyArray);
321
// Type: Array<1 | 'test' | true | 'hello'>
322
// Value: [1, 'test', true, 'hello']
323
324
// Configuration with defaults
325
interface PartialConfig {
326
host?: string | null;
327
port?: number | null;
328
secure?: boolean | null;
329
}
330
331
function applyConfigDefaults(config: PartialConfig): Required<PartialConfig> {
332
return {
333
host: isFalsy(config.host) ? 'localhost' : config.host,
334
port: isFalsy(config.port) ? 8080 : config.port,
335
secure: isFalsy(config.secure) ? false : config.secure
336
};
337
}
338
339
// Conditional rendering helper
340
function renderIfTruthy<T>(value: T, render: (val: Exclude<T, Falsy>) => JSX.Element): JSX.Element | null {
341
if (isFalsy(value)) {
342
return null;
343
}
344
return render(value as Exclude<T, Falsy>);
345
}
346
```
347
348
### isNullish
349
350
Runtime type guard to check if a value is nullish (null or undefined).
351
352
```typescript { .api }
353
function isNullish(val: unknown): val is Nullish;
354
```
355
356
**Usage:**
357
358
```typescript
359
// Basic usage
360
const values = [null, undefined, 0, '', false, 'hello', 1, {}];
361
362
const nullishValues = values.filter(isNullish);
363
// Type: Nullish[]
364
// Contains: [null, undefined]
365
366
const nonNullishValues = values.filter(val => !isNullish(val));
367
// Type: unknown[] (but we know they're not nullish)
368
// Contains: [0, '', false, 'hello', 1, {}]
369
370
// Nullish coalescing with type safety
371
function safeAccess<T>(value: T | Nullish, defaultValue: T): T {
372
if (isNullish(value)) {
373
return defaultValue;
374
}
375
return value; // TypeScript knows value is T here
376
}
377
378
const result1 = safeAccess(null, 'default'); // Result: 'default'
379
const result2 = safeAccess(undefined, 'default'); // Result: 'default'
380
const result3 = safeAccess('value', 'default'); // Result: 'value'
381
const result4 = safeAccess(0, 42); // Result: 0 (zero is not nullish)
382
383
// Optional property processing
384
interface User {
385
id: number;
386
name?: string;
387
email?: string;
388
avatar?: string;
389
}
390
391
function processUser(user: User): Required<User> {
392
return {
393
id: user.id,
394
name: isNullish(user.name) ? 'Anonymous' : user.name,
395
email: isNullish(user.email) ? 'no-email@example.com' : user.email,
396
avatar: isNullish(user.avatar) ? '/default-avatar.png' : user.avatar
397
};
398
}
399
400
// Database result processing
401
type DatabaseResult<T> = T | null | undefined;
402
403
function processResults<T>(results: DatabaseResult<T>[]): T[] {
404
return results.filter((result): result is T => !isNullish(result));
405
}
406
407
const dbResults: DatabaseResult<string>[] = ['user1', null, 'user2', undefined, 'user3'];
408
const validResults = processResults(dbResults);
409
// Type: string[]
410
// Value: ['user1', 'user2', 'user3']
411
412
// API response handling
413
interface ApiResponse<T> {
414
data?: T;
415
error?: string;
416
status: number;
417
}
418
419
function extractData<T>(response: ApiResponse<T>): T | null {
420
if (response.status !== 200) {
421
return null;
422
}
423
424
if (isNullish(response.data)) {
425
return null;
426
}
427
428
return response.data; // TypeScript knows data is T here
429
}
430
431
// Form data validation
432
function validateNonNullishFields<T extends Record<string, any>>(
433
data: T
434
): Record<keyof T, Exclude<T[keyof T], Nullish>> | string[] {
435
const errors: string[] = [];
436
const validated = {} as any;
437
438
for (const [key, value] of Object.entries(data)) {
439
if (isNullish(value)) {
440
errors.push(`${key} is required`);
441
} else {
442
validated[key] = value;
443
}
444
}
445
446
return errors.length > 0 ? errors : validated;
447
}
448
```
449
450
## Combined Usage Examples
451
452
### Type-Safe Data Processing Pipeline
453
454
```typescript
455
// Comprehensive data processing using all utilities
456
interface RawData {
457
id?: number | null;
458
name?: string | null;
459
email?: string | null;
460
score?: number | null;
461
metadata?: Record<string, unknown> | null;
462
}
463
464
function processRawData(items: RawData[]): ProcessedData[] {
465
return items
466
.filter(item => !isNullish(item))
467
.map(item => {
468
// Extract primitive fields
469
const primitiveFields: Record<string, Primitive> = {};
470
const complexFields: Record<string, unknown> = {};
471
472
for (const [key, value] of Object.entries(item)) {
473
if (!isNullish(value)) {
474
if (isPrimitive(value)) {
475
primitiveFields[key] = value;
476
} else {
477
complexFields[key] = value;
478
}
479
}
480
}
481
482
return {
483
id: primitiveFields.id ?? 0,
484
name: isFalsy(primitiveFields.name) ? 'Unknown' : primitiveFields.name as string,
485
email: isFalsy(primitiveFields.email) ? null : primitiveFields.email as string,
486
score: primitiveFields.score ?? 0,
487
hasMetadata: !isNullish(complexFields.metadata)
488
};
489
});
490
}
491
492
interface ProcessedData {
493
id: number;
494
name: string;
495
email: string | null;
496
score: number;
497
hasMetadata: boolean;
498
}
499
```
500
501
### Type Guard Composition
502
503
```typescript
504
// Combining type guards for complex validation
505
function isValidPrimitive(value: unknown): value is Exclude<Primitive, Nullish | Falsy> {
506
return isPrimitive(value) && !isNullish(value) && !isFalsy(value);
507
}
508
509
function isValidString(value: unknown): value is string {
510
return typeof value === 'string' && !isFalsy(value);
511
}
512
513
function isValidNumber(value: unknown): value is number {
514
return typeof value === 'number' && !isFalsy(value) && !isNaN(value);
515
}
516
517
// Usage in validation schemas
518
interface ValidationSchema {
519
[key: string]: (value: unknown) => boolean;
520
}
521
522
const userValidation: ValidationSchema = {
523
id: isValidNumber,
524
name: isValidString,
525
email: (value): value is string =>
526
isValidString(value) && /\S+@\S+\.\S+/.test(value),
527
age: (value): value is number =>
528
isValidNumber(value) && value >= 0 && value <= 150
529
};
530
531
function validateUser(userData: Record<string, unknown>): boolean {
532
return Object.entries(userValidation).every(([key, validator]) =>
533
validator(userData[key])
534
);
535
}
536
```
537
538
## Deprecated Functions
539
540
### getReturnOfExpression (Deprecated)
541
542
**Deprecated** function for inferring return types from expressions. Use TypeScript's built-in `ReturnType<T>` or `$Call` API instead.
543
544
```typescript { .api }
545
function getReturnOfExpression<RT>(expression: (...params: any[]) => RT): RT;
546
```
547
548
**Usage:**
549
550
```typescript
551
// DEPRECATED - Do not use in new code
552
import { getReturnOfExpression } from 'utility-types';
553
554
const increment = () => ({ type: 'INCREMENT' as 'INCREMENT' });
555
type IncrementType = typeof getReturnOfExpression<typeof increment>;
556
// Result: { type: "INCREMENT"; }
557
558
// PREFERRED - Use these instead:
559
type IncrementTypeModern1 = ReturnType<typeof increment>;
560
type IncrementTypeModern2 = $Call<typeof increment>;
561
```
562
563
**Migration Guide:**
564
565
```typescript
566
// Old way (deprecated):
567
const myFunction = (x: number) => ({ result: x * 2 });
568
type OldReturnType = typeof getReturnOfExpression<typeof myFunction>;
569
570
// New way (preferred):
571
type NewReturnType = ReturnType<typeof myFunction>;
572
// or
573
type AlternativeReturnType = $Call<typeof myFunction>;
574
```
575
576
**Note**: This function was deprecated in TypeScript v2.8 when `ReturnType<T>` was introduced. It returns `undefined` at runtime but provides correct type information at compile time.
577
```