0
# Pattern Library
1
2
Comprehensive pattern construction utilities including wildcards, type-specific patterns, and combinators for building complex matching logic.
3
4
## Capabilities
5
6
### Wildcard Patterns
7
8
Basic patterns that match entire categories of values.
9
10
```typescript { .api }
11
/**
12
* Wildcard pattern matching any value
13
*/
14
const any: AnyPattern;
15
16
/**
17
* Alias for any wildcard pattern
18
*/
19
const _: AnyPattern;
20
21
/**
22
* String wildcard with chainable methods
23
*/
24
const string: StringPattern;
25
26
/**
27
* Number wildcard with chainable methods
28
*/
29
const number: NumberPattern;
30
31
/**
32
* BigInt wildcard with chainable methods
33
*/
34
const bigint: BigIntPattern;
35
36
/**
37
* Boolean wildcard pattern
38
*/
39
const boolean: BooleanPattern;
40
41
/**
42
* Symbol wildcard pattern
43
*/
44
const symbol: SymbolPattern;
45
46
/**
47
* Matches null or undefined values
48
*/
49
const nullish: NullishPattern;
50
51
/**
52
* Matches any non-null, non-undefined value
53
*/
54
const nonNullable: NonNullablePattern;
55
56
/**
57
* Symbol used for the matcher protocol to create custom patterns
58
*/
59
const matcher: unique symbol;
60
```
61
62
**Usage Examples:**
63
64
```typescript
65
import { match, P } from "ts-pattern";
66
67
// Basic wildcards
68
const handleValue = match(input)
69
.with(P.string, (str) => `string: ${str}`)
70
.with(P.number, (num) => `number: ${num}`)
71
.with(P.boolean, (bool) => `boolean: ${bool}`)
72
.with(P.nullish, () => 'null or undefined')
73
.with(P._, () => 'something else');
74
```
75
76
### String Patterns
77
78
Patterns for matching strings with specific characteristics.
79
80
```typescript { .api }
81
interface StringChainable<pattern> extends Chainable<pattern> {
82
/**
83
* Matches strings starting with prefix
84
* @param prefix - Required string prefix
85
*/
86
startsWith(prefix: string): StringChainable<GuardP<any, `${string}${string}`>>;
87
88
/**
89
* Matches strings ending with suffix
90
* @param suffix - Required string suffix
91
*/
92
endsWith(suffix: string): StringChainable<GuardP<any, `${string}${string}`>>;
93
94
/**
95
* Matches strings with minimum length
96
* @param min - Minimum string length
97
*/
98
minLength(min: number): StringChainable<GuardP<any, string>>;
99
100
/**
101
* Matches strings with exact length
102
* @param len - Exact string length
103
*/
104
length(len: number): StringChainable<GuardP<any, string>>;
105
106
/**
107
* Matches strings with maximum length
108
* @param max - Maximum string length
109
*/
110
maxLength(max: number): StringChainable<GuardP<any, string>>;
111
112
/**
113
* Matches strings containing substring
114
* @param substring - Required substring
115
*/
116
includes(substring: string): StringChainable<GuardP<any, string>>;
117
118
/**
119
* Matches strings against regular expression
120
* @param expression - Regular expression pattern
121
*/
122
regex(expression: string | RegExp): StringChainable<GuardP<any, string>>;
123
}
124
```
125
126
**Usage Examples:**
127
128
```typescript
129
// String pattern chaining
130
const validateInput = match(userInput)
131
.with(P.string.startsWith('http').includes('://'), (url) => validateUrl(url))
132
.with(P.string.regex(/^\d{3}-\d{2}-\d{4}$/), (ssn) => validateSSN(ssn))
133
.with(P.string.minLength(8).maxLength(32), (password) => validatePassword(password))
134
.otherwise(() => 'invalid input');
135
```
136
137
### Number Patterns
138
139
Patterns for matching numbers with specific constraints.
140
141
```typescript { .api }
142
interface NumberChainable<pattern> extends Chainable<pattern> {
143
/**
144
* Matches numbers between min and max (inclusive)
145
* @param min - Minimum value (inclusive)
146
* @param max - Maximum value (inclusive)
147
*/
148
between(min: number, max: number): NumberChainable<GuardP<any, number>>;
149
150
/**
151
* Matches numbers less than max
152
* @param max - Maximum value (exclusive)
153
*/
154
lt(max: number): NumberChainable<GuardP<any, number>>;
155
156
/**
157
* Matches numbers greater than min
158
* @param min - Minimum value (exclusive)
159
*/
160
gt(min: number): NumberChainable<GuardP<any, number>>;
161
162
/**
163
* Matches numbers less than or equal to max
164
* @param max - Maximum value (inclusive)
165
*/
166
lte(max: number): NumberChainable<GuardP<any, number>>;
167
168
/**
169
* Matches numbers greater than or equal to min
170
* @param min - Minimum value (inclusive)
171
*/
172
gte(min: number): NumberChainable<GuardP<any, number>>;
173
174
/**
175
* Matches integer numbers only
176
*/
177
int(): NumberChainable<GuardP<any, number>>;
178
179
/**
180
* Matches finite numbers (excludes Infinity and -Infinity)
181
*/
182
finite(): NumberChainable<GuardP<any, number>>;
183
184
/**
185
* Matches positive numbers (> 0)
186
*/
187
positive(): NumberChainable<GuardP<any, number>>;
188
189
/**
190
* Matches negative numbers (< 0)
191
*/
192
negative(): NumberChainable<GuardP<any, number>>;
193
}
194
```
195
196
**Usage Examples:**
197
198
```typescript
199
// Number pattern chaining
200
const categorizeNumber = match(value)
201
.with(P.number.int().positive(), (n) => `positive integer: ${n}`)
202
.with(P.number.between(0, 100), (n) => `percentage: ${n}%`)
203
.with(P.number.finite().negative(), (n) => `negative: ${n}`)
204
.otherwise(() => 'other number');
205
```
206
207
### BigInt Patterns
208
209
Patterns for matching bigint values with constraints.
210
211
```typescript { .api }
212
interface BigIntChainable<pattern> extends Chainable<pattern> {
213
/**
214
* Matches bigints between min and max (inclusive)
215
*/
216
between(min: bigint, max: bigint): BigIntChainable<GuardP<any, bigint>>;
217
218
/**
219
* Matches bigints less than max
220
*/
221
lt(max: bigint): BigIntChainable<GuardP<any, bigint>>;
222
223
/**
224
* Matches bigints greater than min
225
*/
226
gt(min: bigint): BigIntChainable<GuardP<any, bigint>>;
227
228
/**
229
* Matches bigints less than or equal to max
230
*/
231
lte(max: bigint): BigIntChainable<GuardP<any, bigint>>;
232
233
/**
234
* Matches bigints greater than or equal to min
235
*/
236
gte(min: bigint): BigIntChainable<GuardP<any, bigint>>;
237
238
/**
239
* Matches positive bigints (> 0n)
240
*/
241
positive(): BigIntChainable<GuardP<any, bigint>>;
242
243
/**
244
* Matches negative bigints (< 0n)
245
*/
246
negative(): BigIntChainable<GuardP<any, bigint>>;
247
}
248
```
249
250
### Collection Patterns
251
252
Patterns for matching arrays, sets, and maps.
253
254
```typescript { .api }
255
/**
256
* Matches arrays with optional element pattern
257
* @param pattern - Pattern to match array elements against
258
* @returns Array pattern that can be chained
259
*/
260
function array<input, const pattern extends Pattern<UnwrapArray<input>>>(
261
pattern?: pattern
262
): ArrayChainable<ArrayP<input, pattern>>;
263
264
/**
265
* Matches sets with optional element pattern
266
* @param pattern - Pattern to match set elements against
267
* @returns Set pattern that can be chained
268
*/
269
function set<input, const pattern extends Pattern<UnwrapSet<input>>>(
270
pattern?: pattern
271
): Chainable<SetP<input, pattern>>;
272
273
/**
274
* Matches maps with optional key and value patterns
275
* @param keyPattern - Pattern to match map keys against
276
* @param valuePattern - Pattern to match map values against
277
* @returns Map pattern that can be chained
278
*/
279
function map<
280
input,
281
const keyPattern extends Pattern<UnwrapMapKey<input>>,
282
const valuePattern extends Pattern<UnwrapMapValue<input>>
283
>(
284
keyPattern?: keyPattern,
285
valuePattern?: valuePattern
286
): Chainable<MapP<input, keyPattern, valuePattern>>;
287
288
interface ArrayChainable<pattern> extends Chainable<pattern> {
289
/**
290
* Makes the array pattern optional
291
*/
292
optional(): ArrayChainable<OptionalP<any, pattern>>;
293
294
/**
295
* Selects the matched array elements
296
*/
297
select(key?: string): ArrayChainable<SelectP<string, any, pattern>>;
298
}
299
```
300
301
**Usage Examples:**
302
303
```typescript
304
// Collection patterns
305
const processData = match(input)
306
.with(P.array(P.string), (strings) => strings.join(','))
307
.with(P.array(P.number.positive()), (nums) => nums.reduce((a, b) => a + b))
308
.with(P.set(P.string.startsWith('user:')), (userIds) => loadUsers(userIds))
309
.with(P.map(P.string, P.number), (stringToNum) => Object.fromEntries(stringToNum))
310
.otherwise(() => 'unsupported data structure');
311
```
312
313
### Combinatorial Patterns
314
315
Patterns that combine multiple patterns using logical operations.
316
317
```typescript { .api }
318
/**
319
* Creates a pattern that matches if ALL patterns match (AND logic)
320
* @param patterns - Patterns that must all match
321
* @returns Intersection pattern
322
*/
323
function intersection<
324
input,
325
const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]
326
>(...patterns: patterns): Chainable<AndP<input, patterns>>;
327
328
/**
329
* Creates a pattern that matches if ANY pattern matches (OR logic)
330
* @param patterns - Patterns where at least one must match
331
* @returns Union pattern
332
*/
333
function union<
334
input,
335
const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]
336
>(...patterns: patterns): Chainable<OrP<input, patterns>>;
337
338
/**
339
* Creates a pattern that matches if the sub-pattern does NOT match
340
* @param pattern - Pattern to negate
341
* @returns Negation pattern
342
*/
343
function not<input, const pattern extends Pattern<input>>(
344
pattern: pattern
345
): Chainable<NotP<input, pattern>>;
346
```
347
348
**Usage Examples:**
349
350
```typescript
351
// Combinatorial patterns
352
const validateUser = match(user)
353
.with(
354
P.intersection(
355
{ age: P.number.gte(21) },
356
{ permissions: P.array(P.string.includes('admin')) },
357
{ active: true }
358
),
359
(u) => 'admin user'
360
)
361
.with(
362
P.union(
363
{ type: 'guest' },
364
{ type: 'trial', expiresAt: P.when(d => d > new Date()) }
365
),
366
(u) => 'temporary access'
367
)
368
.with(
369
P.not({ banned: true }),
370
(u) => 'regular user'
371
)
372
.otherwise(() => 'access denied');
373
```
374
375
### Conditional Patterns
376
377
Patterns that use predicates and guards for custom matching logic.
378
379
```typescript { .api }
380
/**
381
* Creates a pattern that matches based on predicate function
382
* @param predicate - Function that returns truthy value for match
383
* @returns Guard pattern with type narrowing
384
*/
385
function when<input, predicate extends (value: input) => unknown>(
386
predicate: predicate
387
): GuardP<
388
input,
389
predicate extends (value: any) => value is infer narrowed ? narrowed : never
390
>;
391
392
/**
393
* Creates a pattern that matches instances of a class
394
* @param classConstructor - Constructor function to match against
395
* @returns Instance pattern
396
*/
397
function instanceOf<T extends AnyConstructor>(
398
classConstructor: T
399
): Chainable<GuardP<unknown, InstanceType<T>>>;
400
401
/**
402
* Enables chainable methods on structural patterns
403
* @param pattern - Structural pattern to make chainable
404
* @returns Chainable pattern with structural matching
405
*/
406
function shape<input, const pattern extends Pattern<input>>(
407
pattern: pattern
408
): Chainable<GuardP<input, InvertPattern<pattern, input>>>;
409
```
410
411
**Usage Examples:**
412
413
```typescript
414
// Conditional patterns
415
const handleError = match(error)
416
.with(P.instanceOf(TypeError), (err) => handleTypeError(err))
417
.with(P.instanceOf(RangeError), (err) => handleRangeError(err))
418
.with(P.when(err => err.code === 'ENOENT'), (err) => handleFileNotFound(err))
419
.with(P.shape({ status: P.number.between(400, 499) }).select(), (err) => handleClientError(err))
420
.otherwise(err => handleGenericError(err));
421
```
422
423
### Optional and Selection Patterns
424
425
Patterns for handling optional values and capturing selections.
426
427
```typescript { .api }
428
/**
429
* Makes a pattern optional (matches undefined or the pattern)
430
* @param pattern - Pattern to make optional
431
* @returns Optional pattern
432
*/
433
function optional<input, const pattern extends Pattern<input>>(
434
pattern: pattern
435
): Chainable<OptionalP<input, pattern>, 'optional'>;
436
437
/**
438
* Captures the matched value for use in handler
439
* @param key - Optional key name for named selection
440
* @param pattern - Optional pattern to match before selection
441
* @returns Selection pattern
442
*/
443
function select(): Chainable<AnonymousSelectP, 'select' | 'or' | 'and'>;
444
function select<input, const pattern extends Pattern<input>>(
445
pattern: pattern
446
): Chainable<SelectP<symbols.anonymousSelectKey, input, pattern>, 'select' | 'or' | 'and'>;
447
function select<input, const pattern extends Pattern<input>>(
448
key: string,
449
pattern: pattern
450
): Chainable<SelectP<string, input, pattern>, 'select' | 'or' | 'and'>;
451
```
452
453
**Usage Examples:**
454
455
```typescript
456
// Optional and selection patterns
457
const processConfig = match(config)
458
.with(
459
{
460
host: P.string,
461
port: P.number.optional(),
462
credentials: P.select('creds', { username: P.string, password: P.string })
463
},
464
({ creds }) => connectWithCredentials(creds.username, creds.password)
465
)
466
.with(
467
{ host: P.string, apiKey: P.select() },
468
(apiKey) => connectWithApiKey(apiKey)
469
)
470
.otherwise(() => 'invalid configuration');
471
```
472
473
### Universal Chainable Methods
474
475
Methods available on most patterns for additional composition.
476
477
```typescript { .api }
478
interface Chainable<pattern, excluded = never> {
479
/**
480
* Makes the pattern optional (if not excluded)
481
*/
482
optional(): excluded extends 'optional' ? never : Chainable<OptionalP<any, pattern>>;
483
484
/**
485
* Creates intersection with another pattern (if not excluded)
486
*/
487
and<P2>(pattern: P2): excluded extends 'and' ? never : Chainable<AndP<any, [pattern, P2]>>;
488
489
/**
490
* Creates union with another pattern (if not excluded)
491
*/
492
or<P2>(pattern: P2): excluded extends 'or' ? never : Chainable<OrP<any, [pattern, P2]>>;
493
494
/**
495
* Captures matched value (if not excluded)
496
*/
497
select(key?: string): excluded extends 'select' ? never : Chainable<SelectP<string, any, pattern>>;
498
}
499
```