> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tailor-platform/app-shell/llms.txt
> Use this file to discover all available pages before exploring further.

# createTypedPaths

> Create a type-safe path builder for file-based routing

Factory function to create type-safe path builders that work with auto-generated route type definitions. This is designed to work with the vite-plugin's `generateTypedRoutes` option.

## Signature

```typescript theme={null}
function createTypedPaths<
  TRoutes extends Record<string, Record<string, string>>
>(): TypedPaths<TRoutes>
```

## Parameters

<ParamField path="TRoutes" type="Record<string, Record<string, string>>" required>
  Type parameter representing the mapping of route paths to their parameter types.

  This is typically auto-generated by the vite-plugin as `RouteParams`.
</ParamField>

## Return Type

<ResponseField name="TypedPaths" type="TypedPaths<TRoutes>">
  An object with a `for()` method for building type-safe paths.

  <ResponseField name="for" type="function">
    Build a URL path with type-checked parameters.

    **Parameters:**

    * `path: string` - Route path template (can include `?query` suffix)
    * `params?: Record<string, string>` - Path parameters (required if route has dynamic segments)

    **Returns:** Resolved URL path string
  </ResponseField>
</ResponseField>

## Examples

### Basic Setup

```ts theme={null}
// routes.generated.ts (auto-generated by vite-plugin)
import { createTypedPaths } from "@tailor-platform/app-shell";

type RouteParams = {
  "/": {};
  "/dashboard": {};
  "/orders/:id": { id: string };
  "/orders/:orderId/items/:itemId": { orderId: string; itemId: string };
};

export const paths = createTypedPaths<RouteParams>();
```

### Static Routes

```ts theme={null}
import { paths } from "./routes.generated";

// Static route - no params needed
paths.for("/dashboard"); // → "/dashboard"
paths.for("/"); // → "/"
```

### Dynamic Routes

```ts theme={null}
import { paths } from "./routes.generated";

// Dynamic route - params required and type-checked
paths.for("/orders/:id", { id: "123" }); // → "/orders/123"

// Multiple dynamic segments
paths.for("/orders/:orderId/items/:itemId", { 
  orderId: "456", 
  itemId: "789" 
}); // → "/orders/456/items/789"
```

### Routes with Query Strings

```ts theme={null}
import { paths } from "./routes.generated";

// Static route with query string
paths.for("/dashboard?tab=overview"); // → "/dashboard?tab=overview"

// Dynamic route with query string
paths.for("/orders/:id?tab=details", { id: "123" }); 
// → "/orders/123?tab=details"

paths.for("/items/:id?tab=details&view=compact", { id: "456" }); 
// → "/items/456?tab=details&view=compact"
```

### URL Encoding

```ts theme={null}
import { paths } from "./routes.generated";

// Dynamic segments are automatically URL-encoded
paths.for("/products/:id", { id: "foo bar" }); 
// → "/products/foo%20bar"

paths.for("/products/:id", { id: "special/chars?#" }); 
// → "/products/special%2Fchars%3F%23"
```

### Catch-all Routes

```ts theme={null}
// Type definition with catch-all segment
type RouteParams = {
  "/docs/*path": { path: string };
};

const paths = createTypedPaths<RouteParams>();

// Catch-all segments preserve slashes, encode individual segments
paths.for("/docs/*path", { path: "api/reference/hooks" });
// → "/docs/api/reference/hooks"

paths.for("/docs/*path", { path: "guide/getting started" });
// → "/docs/guide/getting%20started"
```

### Type Safety

```ts theme={null}
import { paths } from "./routes.generated";

// ✅ Correct usage
paths.for("/dashboard"); 
paths.for("/orders/:id", { id: "123" });

// ❌ TypeScript errors
paths.for("/orders/:id"); 
// Error: params required

paths.for("/orders/:id", { orderId: "123" }); 
// Error: wrong param name (should be 'id')

paths.for("/invalid"); 
// Error: path not found in RouteParams
```

### Usage in Navigation

```tsx theme={null}
import { Link } from "react-router";
import { paths } from "./routes.generated";

const OrdersList = ({ orders }: { orders: Order[] }) => {
  return (
    <div>
      {orders.map((order) => (
        <Link 
          key={order.id} 
          to={paths.for("/orders/:id", { id: order.id })}
        >
          Order {order.id}
        </Link>
      ))}
    </div>
  );
};
```

### Programmatic Navigation

```tsx theme={null}
import { useNavigate } from "react-router";
import { paths } from "./routes.generated";

const ProductCard = ({ productId }: { productId: string }) => {
  const navigate = useNavigate();
  
  const handleClick = () => {
    navigate(paths.for("/products/:id", { id: productId }));
  };
  
  return <button onClick={handleClick}>View Product</button>;
};
```

### Building URLs from Data

```tsx theme={null}
import { paths } from "./routes.generated";

const buildOrderUrl = (orderId: string, itemId?: string) => {
  if (itemId) {
    return paths.for("/orders/:orderId/items/:itemId", { 
      orderId, 
      itemId 
    });
  }
  return paths.for("/orders/:id", { id: orderId });
};

// Usage
buildOrderUrl("123"); // → "/orders/123"
buildOrderUrl("123", "456"); // → "/orders/123/items/456"
```

## TypeScript Types

```typescript theme={null}
// Extract base path (before ?) from a path with query string
type ExtractBasePath<T extends string> = T extends `${infer Base}?${string}`
  ? Base
  : T;

// Check if an object type has no keys
type IsEmptyObject<T> = keyof T extends never ? true : false;

// Type-safe path builder interface
type TypedPaths<TRoutes extends Record<string, Record<string, string>>> = {
  for<
    T extends (keyof TRoutes & string) | `${keyof TRoutes & string}?${string}`,
  >(
    path: T,
    ...params: ExtractBasePath<T> extends keyof TRoutes
      ? IsEmptyObject<TRoutes[ExtractBasePath<T>]> extends true
        ? []
        : [TRoutes[ExtractBasePath<T>]]
      : never
  ): string;
};
```

## Implementation Details

### Path Parameter Replacement

The `for()` method replaces dynamic segments in the path template:

1. **Dynamic segments** (`:paramName`): Replaced with the encoded parameter value
2. **Catch-all segments** (`*paramName`): Replaced with the parameter value, encoding each path segment individually while preserving slashes

### URL Encoding

* Dynamic segments (`:param`) are encoded using `encodeURIComponent()`, which encodes the entire value including slashes
* Catch-all segments (`*param`) split the value on `/`, encode each segment individually, then rejoin with `/` to preserve path structure

## Notes

* This function is designed to work with auto-generated route types from the vite-plugin
* Path parameters are automatically URL-encoded
* Query strings can be included in the path template using `?` syntax
* TypeScript will enforce that all required parameters are provided with correct types
* Empty parameter objects (`{}`) indicate routes with no dynamic segments

## Related

* [Routing & Navigation](/concepts/routing-navigation) - Understanding AppShell's routing system
* [File-based Routing](/concepts/file-based-routing) - Using the vite-plugin for file-based routes
