or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-loading.mderror-handling.mdindex.mdnavigation-links.mdpath-search-utils.mdreact-components.mdreact-hooks.mdroute-definition.mdrouter-creation.mdssr.md

path-search-utils.mddocs/

0

# Path & Search Utilities

1

2

Low-level utilities for path manipulation, search parameter handling, URL processing, and data validation for robust routing functionality.

3

4

## Capabilities

5

6

### Path Manipulation

7

8

Utilities for working with URL paths, including joining, cleaning, and normalization.

9

10

```typescript { .api }

11

/**

12

* Join multiple path segments into a single path

13

* @param paths - Array of path segments to join

14

* @returns Combined path string

15

*/

16

function joinPaths(paths: Array<string | undefined>): string;

17

18

/**

19

* Clean and normalize a path

20

* @param path - Path to clean

21

* @returns Cleaned path string

22

*/

23

function cleanPath(path: string): string;

24

25

/**

26

* Remove leading and trailing slashes from path

27

* @param path - Path to trim

28

* @returns Trimmed path string

29

*/

30

function trimPath(path: string): string;

31

32

/**

33

* Remove leading slashes from path

34

* @param path - Path to trim

35

* @returns Path without leading slashes

36

*/

37

function trimPathLeft(path: string): string;

38

39

/**

40

* Remove trailing slashes from path

41

* @param path - Path to trim

42

* @returns Path without trailing slashes

43

*/

44

function trimPathRight(path: string): string;

45

46

/**

47

* Resolve a relative path against a base path

48

* @param basepath - Base path

49

* @param base - Current base

50

* @param to - Target path

51

* @returns Resolved absolute path

52

*/

53

function resolvePath(basepath: string, base: string, to: string): string;

54

```

55

56

**Usage Examples:**

57

58

```typescript

59

import {

60

joinPaths,

61

cleanPath,

62

trimPath,

63

trimPathLeft,

64

trimPathRight,

65

resolvePath

66

} from "@tanstack/react-router";

67

68

// Join path segments

69

const fullPath = joinPaths(["/api", "users", undefined, "123"]);

70

// Result: "/api/users/123"

71

72

// Clean messy paths

73

const cleaned = cleanPath("//api///users//123//");

74

// Result: "/api/users/123"

75

76

// Trim slashes

77

const trimmed = trimPath("/path/to/resource/");

78

// Result: "path/to/resource"

79

80

const leftTrimmed = trimPathLeft("///path/to/resource");

81

// Result: "path/to/resource"

82

83

const rightTrimmed = trimPathRight("path/to/resource///");

84

// Result: "path/to/resource"

85

86

// Resolve relative paths

87

const resolved = resolvePath("/app", "/users", "../posts/123");

88

// Result: "/app/posts/123"

89

90

// Resolve from root

91

const absolute = resolvePath("", "/users/123", "../../admin");

92

// Result: "/admin"

93

```

94

95

### Path Parsing and Interpolation

96

97

Utilities for parsing paths and interpolating parameters.

98

99

```typescript { .api }

100

/**

101

* Parse a pathname into segments

102

* @param pathname - Pathname to parse

103

* @returns Array of path segments

104

*/

105

function parsePathname(pathname: string): Array<string>;

106

107

/**

108

* Interpolate path parameters into a path template

109

* @param path - Path template with parameter placeholders

110

* @param params - Parameters to interpolate

111

* @returns Path with parameters filled in

112

*/

113

function interpolatePath(path: string, params: Record<string, any>): string;

114

```

115

116

**Usage Examples:**

117

118

```typescript

119

import { parsePathname, interpolatePath } from "@tanstack/react-router";

120

121

// Parse pathname into segments

122

const segments = parsePathname("/users/123/posts/456");

123

// Result: ["users", "123", "posts", "456"]

124

125

const rootSegments = parsePathname("/");

126

// Result: []

127

128

// Interpolate parameters

129

const userPath = interpolatePath("/users/$userId/posts/$postId", {

130

userId: "123",

131

postId: "456",

132

});

133

// Result: "/users/123/posts/456"

134

135

// With optional parameters

136

const profilePath = interpolatePath("/profile/$userId?", {

137

userId: undefined,

138

});

139

// Result: "/profile"

140

141

// Complex interpolation

142

const complexPath = interpolatePath(

143

"/org/$orgId/project/$projectId/task/$taskId",

144

{

145

orgId: "acme",

146

projectId: "website",

147

taskId: "fix-bug-123",

148

}

149

);

150

// Result: "/org/acme/project/website/task/fix-bug-123"

151

```

152

153

### Search Parameter Processing

154

155

Utilities for parsing, stringifying, and manipulating URL search parameters.

156

157

```typescript { .api }

158

/**

159

* Default search parameter parser

160

* @param searchStr - Search string to parse

161

* @returns Parsed search object

162

*/

163

function defaultParseSearch(searchStr: string): Record<string, any>;

164

165

/**

166

* Default search parameter stringifier

167

* @param search - Search object to stringify

168

* @returns URL search string

169

*/

170

function defaultStringifySearch(search: Record<string, any>): string;

171

172

/**

173

* Create a custom search parser

174

* @param parser - Custom parser function

175

* @returns Search parser function

176

*/

177

function parseSearchWith<T>(

178

parser: (searchStr: string) => T

179

): (searchStr: string) => T;

180

181

/**

182

* Create a custom search stringifier

183

* @param stringify - Custom stringify function

184

* @returns Search stringifier function

185

*/

186

function stringifySearchWith<T>(

187

stringify: (search: T) => string

188

): (search: T) => string;

189

190

type SearchParser<T = any> = (searchStr: string) => T;

191

type SearchSerializer<T = any> = (search: T) => string;

192

```

193

194

**Usage Examples:**

195

196

```typescript

197

import {

198

defaultParseSearch,

199

defaultStringifySearch,

200

parseSearchWith,

201

stringifySearchWith

202

} from "@tanstack/react-router";

203

204

// Default parsing and stringifying

205

const searchObj = defaultParseSearch("?name=john&age=25&active=true");

206

// Result: { name: "john", age: "25", active: "true" }

207

208

const searchStr = defaultStringifySearch({

209

name: "jane",

210

age: 30,

211

tags: ["dev", "react"],

212

});

213

// Result: "name=jane&age=30&tags=dev&tags=react"

214

215

// Custom parser with type conversion

216

const typedParser = parseSearchWith((searchStr: string) => {

217

const params = new URLSearchParams(searchStr);

218

return {

219

page: Number(params.get("page")) || 1,

220

limit: Number(params.get("limit")) || 10,

221

sort: params.get("sort") || "created_at",

222

desc: params.get("desc") === "true",

223

tags: params.getAll("tags"),

224

};

225

});

226

227

const parsed = typedParser("?page=2&limit=20&desc=true&tags=react&tags=routing");

228

// Result: { page: 2, limit: 20, sort: "created_at", desc: true, tags: ["react", "routing"] }

229

230

// Custom stringifier

231

const typedStringifier = stringifySearchWith((search: {

232

page: number;

233

limit: number;

234

filters?: Record<string, any>;

235

}) => {

236

const params = new URLSearchParams();

237

params.set("page", search.page.toString());

238

params.set("limit", search.limit.toString());

239

240

if (search.filters) {

241

Object.entries(search.filters).forEach(([key, value]) => {

242

if (Array.isArray(value)) {

243

value.forEach(v => params.append(key, String(v)));

244

} else {

245

params.set(key, String(value));

246

}

247

});

248

}

249

250

return params.toString();

251

});

252

```

253

254

### Search Parameter Filtering

255

256

Utilities for filtering and manipulating search parameters.

257

258

```typescript { .api }

259

/**

260

* Retain only specific search parameters

261

* @param search - Search object to filter

262

* @param retain - Array of keys to retain

263

* @returns Filtered search object

264

*/

265

function retainSearchParams<T>(

266

search: T,

267

retain: Array<string | number>

268

): Partial<T>;

269

270

/**

271

* Remove specific search parameters

272

* @param search - Search object to filter

273

* @param strip - Array of keys to remove

274

* @returns Filtered search object

275

*/

276

function stripSearchParams<T>(

277

search: T,

278

strip: Array<string | number>

279

): Partial<T>;

280

```

281

282

**Usage Examples:**

283

284

```typescript

285

import { retainSearchParams, stripSearchParams } from "@tanstack/react-router";

286

287

const searchParams = {

288

page: 1,

289

limit: 10,

290

sort: "name",

291

filter: "active",

292

debug: true,

293

internal: "secret",

294

};

295

296

// Retain only specific params

297

const publicParams = retainSearchParams(searchParams, ["page", "limit", "sort", "filter"]);

298

// Result: { page: 1, limit: 10, sort: "name", filter: "active" }

299

300

// Strip sensitive params

301

const cleanParams = stripSearchParams(searchParams, ["debug", "internal"]);

302

// Result: { page: 1, limit: 10, sort: "name", filter: "active" }

303

304

// Use in navigation

305

function NavigateWithCleanParams() {

306

const currentSearch = useSearch();

307

const navigate = useNavigate();

308

309

const navigateToNextPage = () => {

310

const cleanSearch = stripSearchParams(currentSearch, ["debug", "internal"]);

311

navigate({

312

search: {

313

...cleanSearch,

314

page: (cleanSearch.page || 1) + 1,

315

},

316

});

317

};

318

319

return <button onClick={navigateToNextPage}>Next Page</button>;

320

}

321

```

322

323

### Deep Comparison Utilities

324

325

Utilities for deep equality checking and structural sharing.

326

327

```typescript { .api }

328

/**

329

* Deep equality comparison

330

* @param a - First value to compare

331

* @param b - Second value to compare

332

* @param opts - Comparison options

333

* @returns Whether values are deeply equal

334

*/

335

function deepEqual(

336

a: any,

337

b: any,

338

opts?: {

339

partial?: boolean;

340

ignoreUndefined?: boolean;

341

}

342

): boolean;

343

344

/**

345

* Deep equality replacement for structural sharing

346

* @param prev - Previous value

347

* @param next - Next value

348

* @returns Previous value if equal, next value if different

349

*/

350

function replaceEqualDeep<T>(prev: T, next: T): T;

351

352

/**

353

* Check if value is a plain object

354

* @param obj - Value to check

355

* @returns Whether value is a plain object

356

*/

357

function isPlainObject(obj: any): boolean;

358

359

/**

360

* Check if value is a plain array

361

* @param obj - Value to check

362

* @returns Whether value is a plain array

363

*/

364

function isPlainArray(obj: any): boolean;

365

```

366

367

**Usage Examples:**

368

369

```typescript

370

import {

371

deepEqual,

372

replaceEqualDeep,

373

isPlainObject,

374

isPlainArray

375

} from "@tanstack/react-router";

376

377

// Deep equality comparison

378

const obj1 = { a: 1, b: { c: 2, d: [3, 4] } };

379

const obj2 = { a: 1, b: { c: 2, d: [3, 4] } };

380

const obj3 = { a: 1, b: { c: 2, d: [3, 5] } };

381

382

console.log(deepEqual(obj1, obj2)); // true

383

console.log(deepEqual(obj1, obj3)); // false

384

385

// Partial comparison

386

const partial = { a: 1, b: { c: 2 } };

387

const full = { a: 1, b: { c: 2, d: 3 }, e: 4 };

388

console.log(deepEqual(partial, full, { partial: true })); // true

389

390

// Structural sharing for performance

391

const prevState = { users: [1, 2, 3], posts: [4, 5, 6] };

392

const nextState = { users: [1, 2, 3], posts: [4, 5, 7] };

393

394

const optimized = replaceEqualDeep(prevState, nextState);

395

// optimized.users === prevState.users (same reference)

396

// optimized.posts !== prevState.posts (different reference)

397

398

// Type checking

399

console.log(isPlainObject({})); // true

400

console.log(isPlainObject([])); // false

401

console.log(isPlainObject(new Date())); // false

402

403

console.log(isPlainArray([])); // true

404

console.log(isPlainArray({})); // false

405

console.log(isPlainArray("string")); // false

406

```

407

408

### Functional Update Utilities

409

410

Utilities for applying functional updates to data.

411

412

```typescript { .api }

413

/**

414

* Apply a functional update to a value

415

* @param updater - Update function or new value

416

* @param previous - Previous value

417

* @returns Updated value

418

*/

419

function functionalUpdate<T>(

420

updater: T | ((prev: T) => T),

421

previous: T

422

): T;

423

```

424

425

**Usage Examples:**

426

427

```typescript

428

import { functionalUpdate } from "@tanstack/react-router";

429

430

// Simple value update

431

const newValue = functionalUpdate("new", "old");

432

// Result: "new"

433

434

// Functional update

435

const newObj = functionalUpdate(

436

(prev) => ({ ...prev, updated: true }),

437

{ id: 1, name: "test" }

438

);

439

// Result: { id: 1, name: "test", updated: true }

440

441

// Use in search parameter updates

442

function SearchUpdater() {

443

const search = useSearch();

444

const navigate = useNavigate();

445

446

const updateSearch = (updater: (prev: any) => any) => {

447

const newSearch = functionalUpdate(updater, search);

448

navigate({ search: newSearch });

449

};

450

451

return (

452

<div>

453

<button

454

onClick={() =>

455

updateSearch((prev) => ({ ...prev, page: (prev.page || 1) + 1 }))

456

}

457

>

458

Next Page

459

</button>

460

<button

461

onClick={() =>

462

updateSearch((prev) => ({ ...prev, sort: prev.sort === "asc" ? "desc" : "asc" }))

463

}

464

>

465

Toggle Sort

466

</button>

467

</div>

468

);

469

}

470

```

471

472

### URL Construction Utilities

473

474

Utilities for constructing and manipulating URLs.

475

476

```typescript { .api }

477

/**

478

* Root route identifier constant

479

*/

480

const rootRouteId: "__root__";

481

482

/**

483

* Check if value matches a route match object

484

* @param obj - Object to check

485

* @returns Whether object is a route match

486

*/

487

function isMatch(obj: any): obj is RouteMatch;

488

```

489

490

**Usage Examples:**

491

492

```typescript

493

import { rootRouteId, isMatch } from "@tanstack/react-router";

494

495

// Root route identification

496

const isRootRoute = (routeId: string) => routeId === rootRouteId;

497

498

// Route match type checking

499

function processMatches(matches: unknown[]) {

500

const validMatches = matches.filter(isMatch);

501

502

return validMatches.map(match => ({

503

id: match.id,

504

pathname: match.pathname,

505

params: match.params,

506

}));

507

}

508

509

// Use in route tree construction

510

const routeTree = rootRoute.addChildren([

511

homeRoute,

512

aboutRoute,

513

postsRoute.addChildren([

514

postDetailRoute,

515

newPostRoute,

516

]),

517

]);

518

```

519

520

### Route Rendering Utilities

521

522

Utilities for handling route rendering, particularly for not found scenarios.

523

524

```typescript { .api }

525

/**

526

* Renders the appropriate not found component for a route

527

* @param router - Router instance

528

* @param route - Route that triggered not found

529

* @param data - Optional data to pass to not found component

530

* @returns JSX element with not found component

531

*/

532

function renderRouteNotFound(

533

router: AnyRouter,

534

route: AnyRoute,

535

data: any

536

): JSX.Element;

537

```

538

539

**Usage Examples:**

540

541

```typescript

542

import { renderRouteNotFound } from "@tanstack/react-router";

543

544

// Manual not found rendering (typically handled internally)

545

function CustomRouteRenderer({ router, route, error }: {

546

router: AnyRouter;

547

route: AnyRoute;

548

error: any;

549

}) {

550

// Handle not found scenarios

551

if (error?.status === 404) {

552

return renderRouteNotFound(router, route, error);

553

}

554

555

// Handle other rendering scenarios

556

return <route.component />;

557

}

558

```

559

560

## Types

561

562

### Path Types

563

564

```typescript { .api }

565

type Segment = string;

566

567

type RemoveTrailingSlashes<T extends string> = T extends `${infer R}/`

568

? RemoveTrailingSlashes<R>

569

: T;

570

571

type RemoveLeadingSlashes<T extends string> = T extends `/${infer R}`

572

? RemoveLeadingSlashes<R>

573

: T;

574

575

type TrimPath<T extends string> = RemoveTrailingSlashes<RemoveLeadingSlashes<T>>;

576

type TrimPathLeft<T extends string> = RemoveLeadingSlashes<T>;

577

type TrimPathRight<T extends string> = RemoveTrailingSlashes<T>;

578

```

579

580

### Search Types

581

582

```typescript { .api }

583

interface SearchFilter {

584

key: string;

585

value: any;

586

operator: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "nin" | "contains";

587

}

588

589

type SearchSchemaInput = Record<string, any>;

590

591

interface ParsedLocation {

592

pathname: string;

593

search: Record<string, any>;

594

searchStr: string;

595

hash: string;

596

href: string;

597

state?: any;

598

}

599

```

600

601

### Utility Types

602

603

```typescript { .api }

604

type Constrain<T, U> = T extends U ? T : U;

605

606

type Expand<T> = T extends (...args: infer A) => infer R

607

? (...args: Expand<A>) => Expand<R>

608

: T extends object

609

? T extends infer O

610

? { [K in keyof O]: Expand<O[K]> }

611

: never

612

: T;

613

614

type Assign<T, U> = {

615

[K in keyof T]: K extends keyof U ? U[K] : T[K];

616

} & {

617

[K in keyof U]: U[K];

618

};

619

620

type MergeAll<T extends readonly unknown[]> = T extends readonly [

621

infer H,

622

...infer Tail

623

]

624

? H & MergeAll<Tail>

625

: {};

626

627

type IntersectAssign<T, U> = T & U;

628

```