---
title: "TypeScript Generics"
framework: vue
version: "36.1.0"
---

# TypeScript Generics

AG Grid supports TypeScript [Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) for row data, cell values and grid context. This leads to greatly improved developer experience via code completion and compile time validation of row data and cell value properties.

## Row Data: <TData>

Provide a TypeScript interface for row data to the grid to enable auto-completion and type-checking whenever properties are accessed from a row `data` variable. There are multiple ways to configure the generic interface: via the `GridOptions<TData>` interface, via other individual interfaces and finally via framework components.

In the examples below we will use the `ICar` interface to represent row data.

```js
// Row Data interface
interface ICar {
    make: string;
    model: string;
    price: number;
}
```

### Configure via GridOptions

Set the row data type on the grid options interface via `GridOptions<ICar>`. The `ICar` interface will then be used throughout the grid options whenever row data is present. This is true for: properties, callbacks, events and the gridApi.

```js
// Pass ICar to GridOptions as a generic
const gridOptions: GridOptions<ICar> = {
    // rowData is typed as ICar[]
    rowData: [ { make: 'Ford', model: 'Galaxy', price: 20000 } ],

    // Callback with params type: GetRowIdParams<ICar>
    getRowId: (params) => {
        // params.data : ICar
        return params.data.make + params.data.model;
    },

    // Event with type: RowSelectedEvent<ICar>
    onRowSelected: (event) => {
        // event.data: ICar | undefined
        if (event.data) {
            const price = event.data.price;
        }
    }
}

// Grid Api methods use ICar interface
function onSelection() {
    // api.getSelectedRows() : ICar[]
    const cars: ICar[] = api!.getSelectedRows();
}
```

> **Note**
>
> You do not need to explicitly type callbacks and events that are defined as part of `GridOptions`. TypeScript will correctly pass the generic type down the interface hierarchy.

### Configure via Interfaces

Each interface that accepts a generic type of `TData` can also be configured individually. For example, an event handler function can accept the generic parameter on the event `RowSelectedEvent`.

```ts
function onRowSelected(event: RowSelectedEvent<ICar>) {
    if (event.data) {
        // event.data: ICar | undefined
        const price = event.data.price;
    }
}
```

### Type: TData | undefined

For a number of events and callbacks, when a generic interface is provided, the `data` property is typed as `TData | undefined` instead of `any`. The undefined is required because it is possible for the `data` property to be undefined under certain grid configurations.

A good example of this is [Row Grouping](https://www.ag-grid.com/vue-data-grid/grouping/). The `onRowSelected` event is fired for both leaf and group rows. Data is only present on leaf nodes and so the event should be written to handle cases when `data` is undefined for groups.

```js
function onRowSelected(event: RowSelectedEvent<ICar>) {
    // event.data is typed as ICar | undefined
    if (event.data) {
        // Leaf row with data
        const price = event.data.price;
    } else {
        // This is a group row
    }
}
```

## Cell Value: <TValue>

When working with cell values it is possible to provide a generic interface for the `value` property. While this will often be a primitive type, such as `string` or `number`, it can also be a complex type. Using a generic for the cell value will enable auto-completion and type-checking.

### Configure via ColDef

Set the cell value type directly on the column definition interface via `ColDef<TData, TValue>` (e.g. `ColDef<ICar, number>`). This will be passed through to all properties in the column definition that use the cell value type.

### Configure via Interfaces

Each interface that accepts a generic type of `TValue` can also be configured individually. Here is an example of a `valueFormatter` for the price column. The `params.value` property is correctly typed as a `number` due to typing the params argument as `ValueFormatterParams<ICar, number>`.

```js
const colDefs: ColDef<ICar>[] = [
    {
        field: 'price',
        valueFormatter: (params: ValueFormatterParams<ICar, number>) => {
            // params.value : number
            return "£" + params.value;
        }
    }
];
```

The `TValue` generic type is also supported for cell renderers / editors by `ICellRendererParams<TData, TValue>` and `ICellEditorParams<TData, TValue>` respectively.

### Typed: TValue | null | undefined

For a number of events and callbacks when a generic interface is provided, the `value` property is typed as `TValue | null | undefined` instead of `any`. This is because it is possible for the `value` property to be `undefined` under certain grid configurations, and it can be `null` when cell editing is enabled and the value has been deleted.

## Context: <TContext>

The grid options property `context` can be used to provided additional information to grid callbacks and event handlers implemented by your application. See [Context](https://www.ag-grid.com/vue-data-grid/context/) for more details. The `params.context` property can be typed via the `TContext` generic parameter.

### Configure via Interfaces

The generic parameter `TContext` needs to be explicitly provided to each interface where it is used. For example, an event handler function can accept the generic parameter on the event `RowSelectedEvent<TData, TContext>`.

```js
// Define the interface for your context
interface IDiscountRate {
    discount: number;
}

// Set the context property on gridOptions using `as` to apply the type
const gridOptions: GridOptions<ICar> {
    context: {
        discount: 0.9
    } as IDiscountRate;
}

// Provide to the interface to the TContext generic parameter to type the params.context property
function onRowSelected(event: RowSelectedEvent<ICar, IDiscountRate>) {
    if (event.data) {
        // event.context.discount is typed as number
        const price = event.data.price * event.context.discount;
    }
}
```

## Generic Type Example

Inspect the code in the following example or open in Plunker to experiment with generic typing yourself.

- `rowData` is typed using the `ICar` interface via `TData`.
- `valueFormatter` types the `value` property as `number` via `TValue`.
- `onRowSelected` event handler uses the `IDiscountRate` interface via `TContext`.

Also note that the `Log Selected Cars` button will log the selected cars to the developer console.

#### Generic Types

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  RowSelectedEvent,
  RowSelectionModule,
  RowSelectionOptions,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([RowSelectionModule, ClientSideRowModelModule]);

interface ICar {
  make: string;
  model: string;
  price: number;
}
interface IDiscountRate {
  discount: number;
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onShowSelection()">Log Selected Cars</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :columnDefs="columnDefs"
        :rowData="rowData"
        :rowSelection="rowSelection"
        :context="context"
        :getRowId="getRowId"
        @row-selected="onRowSelected"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<ICar> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { headerName: "Make", field: "make" },
      { headerName: "Model", field: "model" },
      {
        headerName: "Price",
        field: "price",
        valueFormatter: (params: ValueFormatterParams<ICar, number>) => {
          // params.value: number
          return "£" + params.value;
        },
      },
    ]);
    const rowData = ref<ICar[] | null>([
      { make: "Toyota", model: "Celica", price: 35000 },
      { make: "Ford", model: "Mondeo", price: 32000 },
      { make: "Porsche", model: "Boxster", price: 72000 },
    ]);
    const rowSelection = ref<RowSelectionOptions | "single" | "multiple">({
      mode: "multiRow",
    });
    const context = ref({
      discount: 0.9,
    } as IDiscountRate);
    const getRowId = ref<GetRowIdFunc>((params: GetRowIdParams<ICar>) => {
      // params.data : ICar
      return params.data.make + params.data.model;
    });

    function onRowSelected(event: RowSelectedEvent<ICar, IDiscountRate>) {
      // event.data: ICar | undefined
      if (event.data && event.node.isSelected()) {
        const price = event.data.price;
        // event.context: IContext
        const discountRate = event.context.discount;
        console.log("Price with 10% discount:", price * discountRate);
      }
    }
    function onShowSelection() {
      // api.getSelectedRows() : ICar[]
      const cars: ICar[] = gridApi.value!.getSelectedRows();
      console.log(
        "Selected cars are",
        cars.map((c) => `${c.make} ${c.model}`),
      );
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      rowData,
      rowSelection,
      context,
      getRowId,
      onGridReady,
      onRowSelected,
      onShowSelection,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Generic Types](https://www.ag-grid.com/examples/typescript-generics/generic/vue3)

## Fallback Default

If generic interfaces are not provided then the grid will use the default type of `any`. This means that generics in AG Grid are completely optional. GridOptions is defined as `GridOptions<TData = any>`, so if a generic parameter is not provided then `any` is used in its place for row data properties.

Likewise for cell values, if a generic parameter is not provided, `any` is used for the value property. For example, cell renderer params are defined as `ICellRendererParams<TData = any, TValue = any>`.
