# filter

```ts
import { filter } from 'cx/data';
```


`filter` performs immutable array filtering. Unlike native `Array.filter()`, it returns the original array reference if no items are removed, enabling efficient change detection.

```tsx
import { filter, createModel } from "cx/data";
import { Controller } from "cx/ui";
import { Button, Grid, NumberField } from "cx/widgets";

interface Item {
  id: number;
  name: string;
  value: number;
}

interface Model {
  items: Item[];
  threshold: number;
}

const m = createModel<Model>();

class PageController extends Controller {
  onInit() {
    this.store.set(m.items, [
      { id: 1, name: "Alpha", value: 10 },
      { id: 2, name: "Beta", value: 25 },
      { id: 3, name: "Gamma", value: 5 },
      { id: 4, name: "Delta", value: 30 },
      { id: 5, name: "Epsilon", value: 15 },
    ]);
    this.store.set(m.threshold, 15);
  }

  filterAboveThreshold() {
    const threshold = this.store.get(m.threshold);
    this.store.update(m.items, (items) =>
      filter(items, (item) => item.value >= threshold),
    );
  }

  filterEvenIds() {
    this.store.update(m.items, (items) =>
      filter(items, (item) => item.id % 2 === 0),
    );
  }

  reset() {
    this.onInit();
  }
}

export default (
  <div controller={PageController}>
    <Grid
      records={m.items}
      columns={[
        { header: "ID", field: "id", align: "center" },
        { header: "Name", field: "name" },
        { header: "Value", field: "value", align: "right" },
      ]}
    />
    <div style="margin-top: 16px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap">
      <span>Threshold:</span>
      <NumberField value={m.threshold} style="width: 60px" />
      <Button onClick="filterAboveThreshold">Keep ≥ Threshold</Button>
      <Button onClick="filterEvenIds">Keep Even IDs</Button>
      <Button onClick="reset">Reset</Button>
    </div>
  </div>
);

```

## Signature

```ts
function filter<T>(
  array: T[],
  callback: (item: T, index: number, array: T[]) => boolean,
): T[];
```

## Parameters

| Parameter  | Type       | Description                                     |
| ---------- | ---------- | ----------------------------------------------- |
| `array`    | `T[]`      | The array to filter.                            |
| `callback` | `function` | Predicate function. Return `true` to keep item. |

## Return Value

Returns a new array with items that pass the test, or the **original array** if all items pass (preserves reference equality).

## Examples

### Basic usage

```ts
const items = [1, 2, 3, 4, 5];
const result = filter(items, (n) => n > 2);
// [3, 4, 5]
```

### Reference preservation

```ts
const items = [1, 2, 3];

// All items pass - returns same reference
const result1 = filter(items, (n) => n > 0);
console.log(result1 === items); // true

// Some items removed - returns new array
const result2 = filter(items, (n) => n > 1);
console.log(result2 === items); // false
```

### With null array

```ts
const result = filter(null, (n) => n > 0);
// null
```

## Why Use This Instead of Array.filter()?

The native `Array.filter()` always returns a new array, even if no items are removed. This can cause unnecessary re-renders in reactive frameworks since reference equality checks fail.

```ts
const items = [1, 2, 3];

// Native filter - always new array
const native = items.filter((n) => n > 0);
console.log(native === items); // false (always)

// cx filter - preserves reference if unchanged
const cx = filter(items, (n) => n > 0);
console.log(cx === items); // true
```

## See Also

- [updateArray](/docs/utilities/update-array) - Update and optionally remove items
- [append](/docs/utilities/append) - Add items to array