npm-tanstack--react-router

Description
Modern and scalable routing for React applications with built-in data fetching, caching, and state management capabilities
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/npm-tanstack--react-router@1.132.0

path-search-utils.md docs/

1
# Path & Search Utilities
2
3
Low-level utilities for path manipulation, search parameter handling, URL processing, and data validation for robust routing functionality.
4
5
## Capabilities
6
7
### Path Manipulation
8
9
Utilities for working with URL paths, including joining, cleaning, and normalization.
10
11
```typescript { .api }
12
/**
13
* Join multiple path segments into a single path
14
* @param paths - Array of path segments to join
15
* @returns Combined path string
16
*/
17
function joinPaths(paths: Array<string | undefined>): string;
18
19
/**
20
* Clean and normalize a path
21
* @param path - Path to clean
22
* @returns Cleaned path string
23
*/
24
function cleanPath(path: string): string;
25
26
/**
27
* Remove leading and trailing slashes from path
28
* @param path - Path to trim
29
* @returns Trimmed path string
30
*/
31
function trimPath(path: string): string;
32
33
/**
34
* Remove leading slashes from path
35
* @param path - Path to trim
36
* @returns Path without leading slashes
37
*/
38
function trimPathLeft(path: string): string;
39
40
/**
41
* Remove trailing slashes from path
42
* @param path - Path to trim
43
* @returns Path without trailing slashes
44
*/
45
function trimPathRight(path: string): string;
46
47
/**
48
* Resolve a relative path against a base path
49
* @param basepath - Base path
50
* @param base - Current base
51
* @param to - Target path
52
* @returns Resolved absolute path
53
*/
54
function resolvePath(basepath: string, base: string, to: string): string;
55
```
56
57
**Usage Examples:**
58
59
```typescript
60
import {
61
joinPaths,
62
cleanPath,
63
trimPath,
64
trimPathLeft,
65
trimPathRight,
66
resolvePath
67
} from "@tanstack/react-router";
68
69
// Join path segments
70
const fullPath = joinPaths(["/api", "users", undefined, "123"]);
71
// Result: "/api/users/123"
72
73
// Clean messy paths
74
const cleaned = cleanPath("//api///users//123//");
75
// Result: "/api/users/123"
76
77
// Trim slashes
78
const trimmed = trimPath("/path/to/resource/");
79
// Result: "path/to/resource"
80
81
const leftTrimmed = trimPathLeft("///path/to/resource");
82
// Result: "path/to/resource"
83
84
const rightTrimmed = trimPathRight("path/to/resource///");
85
// Result: "path/to/resource"
86
87
// Resolve relative paths
88
const resolved = resolvePath("/app", "/users", "../posts/123");
89
// Result: "/app/posts/123"
90
91
// Resolve from root
92
const absolute = resolvePath("", "/users/123", "../../admin");
93
// Result: "/admin"
94
```
95
96
### Path Parsing and Interpolation
97
98
Utilities for parsing paths and interpolating parameters.
99
100
```typescript { .api }
101
/**
102
* Parse a pathname into segments
103
* @param pathname - Pathname to parse
104
* @returns Array of path segments
105
*/
106
function parsePathname(pathname: string): Array<string>;
107
108
/**
109
* Interpolate path parameters into a path template
110
* @param path - Path template with parameter placeholders
111
* @param params - Parameters to interpolate
112
* @returns Path with parameters filled in
113
*/
114
function interpolatePath(path: string, params: Record<string, any>): string;
115
```
116
117
**Usage Examples:**
118
119
```typescript
120
import { parsePathname, interpolatePath } from "@tanstack/react-router";
121
122
// Parse pathname into segments
123
const segments = parsePathname("/users/123/posts/456");
124
// Result: ["users", "123", "posts", "456"]
125
126
const rootSegments = parsePathname("/");
127
// Result: []
128
129
// Interpolate parameters
130
const userPath = interpolatePath("/users/$userId/posts/$postId", {
131
userId: "123",
132
postId: "456",
133
});
134
// Result: "/users/123/posts/456"
135
136
// With optional parameters
137
const profilePath = interpolatePath("/profile/$userId?", {
138
userId: undefined,
139
});
140
// Result: "/profile"
141
142
// Complex interpolation
143
const complexPath = interpolatePath(
144
"/org/$orgId/project/$projectId/task/$taskId",
145
{
146
orgId: "acme",
147
projectId: "website",
148
taskId: "fix-bug-123",
149
}
150
);
151
// Result: "/org/acme/project/website/task/fix-bug-123"
152
```
153
154
### Search Parameter Processing
155
156
Utilities for parsing, stringifying, and manipulating URL search parameters.
157
158
```typescript { .api }
159
/**
160
* Default search parameter parser
161
* @param searchStr - Search string to parse
162
* @returns Parsed search object
163
*/
164
function defaultParseSearch(searchStr: string): Record<string, any>;
165
166
/**
167
* Default search parameter stringifier
168
* @param search - Search object to stringify
169
* @returns URL search string
170
*/
171
function defaultStringifySearch(search: Record<string, any>): string;
172
173
/**
174
* Create a custom search parser
175
* @param parser - Custom parser function
176
* @returns Search parser function
177
*/
178
function parseSearchWith<T>(
179
parser: (searchStr: string) => T
180
): (searchStr: string) => T;
181
182
/**
183
* Create a custom search stringifier
184
* @param stringify - Custom stringify function
185
* @returns Search stringifier function
186
*/
187
function stringifySearchWith<T>(
188
stringify: (search: T) => string
189
): (search: T) => string;
190
191
type SearchParser<T = any> = (searchStr: string) => T;
192
type SearchSerializer<T = any> = (search: T) => string;
193
```
194
195
**Usage Examples:**
196
197
```typescript
198
import {
199
defaultParseSearch,
200
defaultStringifySearch,
201
parseSearchWith,
202
stringifySearchWith
203
} from "@tanstack/react-router";
204
205
// Default parsing and stringifying
206
const searchObj = defaultParseSearch("?name=john&age=25&active=true");
207
// Result: { name: "john", age: "25", active: "true" }
208
209
const searchStr = defaultStringifySearch({
210
name: "jane",
211
age: 30,
212
tags: ["dev", "react"],
213
});
214
// Result: "name=jane&age=30&tags=dev&tags=react"
215
216
// Custom parser with type conversion
217
const typedParser = parseSearchWith((searchStr: string) => {
218
const params = new URLSearchParams(searchStr);
219
return {
220
page: Number(params.get("page")) || 1,
221
limit: Number(params.get("limit")) || 10,
222
sort: params.get("sort") || "created_at",
223
desc: params.get("desc") === "true",
224
tags: params.getAll("tags"),
225
};
226
});
227
228
const parsed = typedParser("?page=2&limit=20&desc=true&tags=react&tags=routing");
229
// Result: { page: 2, limit: 20, sort: "created_at", desc: true, tags: ["react", "routing"] }
230
231
// Custom stringifier
232
const typedStringifier = stringifySearchWith((search: {
233
page: number;
234
limit: number;
235
filters?: Record<string, any>;
236
}) => {
237
const params = new URLSearchParams();
238
params.set("page", search.page.toString());
239
params.set("limit", search.limit.toString());
240
241
if (search.filters) {
242
Object.entries(search.filters).forEach(([key, value]) => {
243
if (Array.isArray(value)) {
244
value.forEach(v => params.append(key, String(v)));
245
} else {
246
params.set(key, String(value));
247
}
248
});
249
}
250
251
return params.toString();
252
});
253
```
254
255
### Search Parameter Filtering
256
257
Utilities for filtering and manipulating search parameters.
258
259
```typescript { .api }
260
/**
261
* Retain only specific search parameters
262
* @param search - Search object to filter
263
* @param retain - Array of keys to retain
264
* @returns Filtered search object
265
*/
266
function retainSearchParams<T>(
267
search: T,
268
retain: Array<string | number>
269
): Partial<T>;
270
271
/**
272
* Remove specific search parameters
273
* @param search - Search object to filter
274
* @param strip - Array of keys to remove
275
* @returns Filtered search object
276
*/
277
function stripSearchParams<T>(
278
search: T,
279
strip: Array<string | number>
280
): Partial<T>;
281
```
282
283
**Usage Examples:**
284
285
```typescript
286
import { retainSearchParams, stripSearchParams } from "@tanstack/react-router";
287
288
const searchParams = {
289
page: 1,
290
limit: 10,
291
sort: "name",
292
filter: "active",
293
debug: true,
294
internal: "secret",
295
};
296
297
// Retain only specific params
298
const publicParams = retainSearchParams(searchParams, ["page", "limit", "sort", "filter"]);
299
// Result: { page: 1, limit: 10, sort: "name", filter: "active" }
300
301
// Strip sensitive params
302
const cleanParams = stripSearchParams(searchParams, ["debug", "internal"]);
303
// Result: { page: 1, limit: 10, sort: "name", filter: "active" }
304
305
// Use in navigation
306
function NavigateWithCleanParams() {
307
const currentSearch = useSearch();
308
const navigate = useNavigate();
309
310
const navigateToNextPage = () => {
311
const cleanSearch = stripSearchParams(currentSearch, ["debug", "internal"]);
312
navigate({
313
search: {
314
...cleanSearch,
315
page: (cleanSearch.page || 1) + 1,
316
},
317
});
318
};
319
320
return <button onClick={navigateToNextPage}>Next Page</button>;
321
}
322
```
323
324
### Deep Comparison Utilities
325
326
Utilities for deep equality checking and structural sharing.
327
328
```typescript { .api }
329
/**
330
* Deep equality comparison
331
* @param a - First value to compare
332
* @param b - Second value to compare
333
* @param opts - Comparison options
334
* @returns Whether values are deeply equal
335
*/
336
function deepEqual(
337
a: any,
338
b: any,
339
opts?: {
340
partial?: boolean;
341
ignoreUndefined?: boolean;
342
}
343
): boolean;
344
345
/**
346
* Deep equality replacement for structural sharing
347
* @param prev - Previous value
348
* @param next - Next value
349
* @returns Previous value if equal, next value if different
350
*/
351
function replaceEqualDeep<T>(prev: T, next: T): T;
352
353
/**
354
* Check if value is a plain object
355
* @param obj - Value to check
356
* @returns Whether value is a plain object
357
*/
358
function isPlainObject(obj: any): boolean;
359
360
/**
361
* Check if value is a plain array
362
* @param obj - Value to check
363
* @returns Whether value is a plain array
364
*/
365
function isPlainArray(obj: any): boolean;
366
```
367
368
**Usage Examples:**
369
370
```typescript
371
import {
372
deepEqual,
373
replaceEqualDeep,
374
isPlainObject,
375
isPlainArray
376
} from "@tanstack/react-router";
377
378
// Deep equality comparison
379
const obj1 = { a: 1, b: { c: 2, d: [3, 4] } };
380
const obj2 = { a: 1, b: { c: 2, d: [3, 4] } };
381
const obj3 = { a: 1, b: { c: 2, d: [3, 5] } };
382
383
console.log(deepEqual(obj1, obj2)); // true
384
console.log(deepEqual(obj1, obj3)); // false
385
386
// Partial comparison
387
const partial = { a: 1, b: { c: 2 } };
388
const full = { a: 1, b: { c: 2, d: 3 }, e: 4 };
389
console.log(deepEqual(partial, full, { partial: true })); // true
390
391
// Structural sharing for performance
392
const prevState = { users: [1, 2, 3], posts: [4, 5, 6] };
393
const nextState = { users: [1, 2, 3], posts: [4, 5, 7] };
394
395
const optimized = replaceEqualDeep(prevState, nextState);
396
// optimized.users === prevState.users (same reference)
397
// optimized.posts !== prevState.posts (different reference)
398
399
// Type checking
400
console.log(isPlainObject({})); // true
401
console.log(isPlainObject([])); // false
402
console.log(isPlainObject(new Date())); // false
403
404
console.log(isPlainArray([])); // true
405
console.log(isPlainArray({})); // false
406
console.log(isPlainArray("string")); // false
407
```
408
409
### Functional Update Utilities
410
411
Utilities for applying functional updates to data.
412
413
```typescript { .api }
414
/**
415
* Apply a functional update to a value
416
* @param updater - Update function or new value
417
* @param previous - Previous value
418
* @returns Updated value
419
*/
420
function functionalUpdate<T>(
421
updater: T | ((prev: T) => T),
422
previous: T
423
): T;
424
```
425
426
**Usage Examples:**
427
428
```typescript
429
import { functionalUpdate } from "@tanstack/react-router";
430
431
// Simple value update
432
const newValue = functionalUpdate("new", "old");
433
// Result: "new"
434
435
// Functional update
436
const newObj = functionalUpdate(
437
(prev) => ({ ...prev, updated: true }),
438
{ id: 1, name: "test" }
439
);
440
// Result: { id: 1, name: "test", updated: true }
441
442
// Use in search parameter updates
443
function SearchUpdater() {
444
const search = useSearch();
445
const navigate = useNavigate();
446
447
const updateSearch = (updater: (prev: any) => any) => {
448
const newSearch = functionalUpdate(updater, search);
449
navigate({ search: newSearch });
450
};
451
452
return (
453
<div>
454
<button
455
onClick={() =>
456
updateSearch((prev) => ({ ...prev, page: (prev.page || 1) + 1 }))
457
}
458
>
459
Next Page
460
</button>
461
<button
462
onClick={() =>
463
updateSearch((prev) => ({ ...prev, sort: prev.sort === "asc" ? "desc" : "asc" }))
464
}
465
>
466
Toggle Sort
467
</button>
468
</div>
469
);
470
}
471
```
472
473
### URL Construction Utilities
474
475
Utilities for constructing and manipulating URLs.
476
477
```typescript { .api }
478
/**
479
* Root route identifier constant
480
*/
481
const rootRouteId: "__root__";
482
483
/**
484
* Check if value matches a route match object
485
* @param obj - Object to check
486
* @returns Whether object is a route match
487
*/
488
function isMatch(obj: any): obj is RouteMatch;
489
```
490
491
**Usage Examples:**
492
493
```typescript
494
import { rootRouteId, isMatch } from "@tanstack/react-router";
495
496
// Root route identification
497
const isRootRoute = (routeId: string) => routeId === rootRouteId;
498
499
// Route match type checking
500
function processMatches(matches: unknown[]) {
501
const validMatches = matches.filter(isMatch);
502
503
return validMatches.map(match => ({
504
id: match.id,
505
pathname: match.pathname,
506
params: match.params,
507
}));
508
}
509
510
// Use in route tree construction
511
const routeTree = rootRoute.addChildren([
512
homeRoute,
513
aboutRoute,
514
postsRoute.addChildren([
515
postDetailRoute,
516
newPostRoute,
517
]),
518
]);
519
```
520
521
### Route Rendering Utilities
522
523
Utilities for handling route rendering, particularly for not found scenarios.
524
525
```typescript { .api }
526
/**
527
* Renders the appropriate not found component for a route
528
* @param router - Router instance
529
* @param route - Route that triggered not found
530
* @param data - Optional data to pass to not found component
531
* @returns JSX element with not found component
532
*/
533
function renderRouteNotFound(
534
router: AnyRouter,
535
route: AnyRoute,
536
data: any
537
): JSX.Element;
538
```
539
540
**Usage Examples:**
541
542
```typescript
543
import { renderRouteNotFound } from "@tanstack/react-router";
544
545
// Manual not found rendering (typically handled internally)
546
function CustomRouteRenderer({ router, route, error }: {
547
router: AnyRouter;
548
route: AnyRoute;
549
error: any;
550
}) {
551
// Handle not found scenarios
552
if (error?.status === 404) {
553
return renderRouteNotFound(router, route, error);
554
}
555
556
// Handle other rendering scenarios
557
return <route.component />;
558
}
559
```
560
561
## Types
562
563
### Path Types
564
565
```typescript { .api }
566
type Segment = string;
567
568
type RemoveTrailingSlashes<T extends string> = T extends `${infer R}/`
569
? RemoveTrailingSlashes<R>
570
: T;
571
572
type RemoveLeadingSlashes<T extends string> = T extends `/${infer R}`
573
? RemoveLeadingSlashes<R>
574
: T;
575
576
type TrimPath<T extends string> = RemoveTrailingSlashes<RemoveLeadingSlashes<T>>;
577
type TrimPathLeft<T extends string> = RemoveLeadingSlashes<T>;
578
type TrimPathRight<T extends string> = RemoveTrailingSlashes<T>;
579
```
580
581
### Search Types
582
583
```typescript { .api }
584
interface SearchFilter {
585
key: string;
586
value: any;
587
operator: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "nin" | "contains";
588
}
589
590
type SearchSchemaInput = Record<string, any>;
591
592
interface ParsedLocation {
593
pathname: string;
594
search: Record<string, any>;
595
searchStr: string;
596
hash: string;
597
href: string;
598
state?: any;
599
}
600
```
601
602
### Utility Types
603
604
```typescript { .api }
605
type Constrain<T, U> = T extends U ? T : U;
606
607
type Expand<T> = T extends (...args: infer A) => infer R
608
? (...args: Expand<A>) => Expand<R>
609
: T extends object
610
? T extends infer O
611
? { [K in keyof O]: Expand<O[K]> }
612
: never
613
: T;
614
615
type Assign<T, U> = {
616
[K in keyof T]: K extends keyof U ? U[K] : T[K];
617
} & {
618
[K in keyof U]: U[K];
619
};
620
621
type MergeAll<T extends readonly unknown[]> = T extends readonly [
622
infer H,
623
...infer Tail
624
]
625
? H & MergeAll<Tail>
626
: {};
627
628
type IntersectAssign<T, U> = T & U;
629
```