# Typed Models



CxJS uses **typed models** to provide type-safe access to data in the store. Instead of using string paths like `"user.firstName"`, you use accessor chains like `m.user.firstName` that are checked by TypeScript.

## Creating a Model Proxy

Use `createModel<T>()` to create a proxy object that mirrors your data structure. The proxy doesn't hold any data — it generates binding paths that connect widgets to the store.

```tsx
import { createModel } from "cx/data";
import { TextField, Button } from "cx/widgets";

interface User {
  firstName: string;
  lastName: string;
}

interface PageModel {
  user: User;
  message: string;
}

const m = createModel<PageModel>();

export default (
  <div class="flex flex-col gap-4">
    <div class="flex gap-2">
      <TextField value={m.user.firstName} placeholder="First name" />
      <TextField value={m.user.lastName} placeholder="Last name" />
    </div>
    <div class="p-3 bg-muted rounded text-sm">
      <strong>Store content</strong>
      <pre class="mt-2" text={(data) => JSON.stringify(data, null, 2)} />
    </div>
  </div>
);

```

When you write `m.user.firstName`, CxJS creates a binding to the path `"user.firstName"` in the store. The TextField reads and writes to this path automatically.

## Why Typed Models?

Typed models provide several benefits over string-based paths:

- **Type safety** — TypeScript catches typos and invalid paths at compile time
- **Autocomplete** — Your editor suggests available properties as you type
- **Refactoring** — Rename a property and all usages update automatically
- **Documentation** — Hover over a property to see its type

## Accessor Methods

Accessor chains provide two useful methods for working with paths:

| Method       | Description                                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `toString()` | Returns the full string path represented by the accessor. Useful when you need to pass paths to APIs that expect strings. |
| `nameOf()`   | Returns only the last segment of the path (the property name).                                                            |

```tsx
import { createModel } from "cx/data";

interface User {
  firstName: string;
  lastName: string;
  email: string;
}

interface PageModel {
  user: User;
  count: number;
}

const m = createModel<PageModel>();

export default (
  <table class="w-full text-sm">
    <thead>
      <tr>
        <th class="text-left py-2 pr-4 border-b border-border">Accessor</th>
        <th class="text-left py-2 border-b border-border">Result</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td class="py-2 pr-4">
          <code class="text-primary">m.user.firstName.toString()</code>
        </td>
        <td class="py-2">
          <code>"{m.user.firstName.toString()}"</code>
        </td>
      </tr>
      <tr>
        <td class="py-2 pr-4">
          <code class="text-primary">m.user.email.toString()</code>
        </td>
        <td class="py-2">
          <code>"{m.user.email.toString()}"</code>
        </td>
      </tr>
      <tr>
        <td class="py-2 pr-4">
          <code class="text-primary">m.count.toString()</code>
        </td>
        <td class="py-2">
          <code>"{m.count.toString()}"</code>
        </td>
      </tr>
      <tr>
        <td class="py-2 pr-4">
          <code class="text-primary">m.user.lastName.nameOf()</code>
        </td>
        <td class="py-2">
          <code>"{m.user.lastName.nameOf()}"</code>
        </td>
      </tr>
      <tr>
        <td class="py-2 pr-4">
          <code class="text-primary">m.count.nameOf()</code>
        </td>
        <td class="py-2">
          <code>"{m.count.nameOf()}"</code>
        </td>
      </tr>
    </tbody>
  </table>
);

```

## Nested Structures

Accessor chains work with deeply nested structures. Define your interfaces to match your data shape:

```tsx
interface Address {
  street: string;
  city: string;
  country: string;
}

interface User {
  name: string;
  address: Address;
}

interface PageModel {
  user: User;
}

const m = createModel<PageModel>();

// Access nested properties
m.user.address.city; // binds to "user.address.city"
```

The proxy automatically generates the correct path regardless of nesting depth.

<Note>
`createModel` can also be imported from `cx/ui`. `createAccessorModelProxy` is available as an alias for backward compatibility.
</Note>