Capítulo 9 de 54
Everything else in TanStack Table's type system flows from your data array's type (TData) — define it once, correctly, and columns/rows/cells get inferred types for free; get the shape wrong and every downstream API loses its inference.
data is an array of row objects; its element type becomes the TData generic threaded through table/column/row/cell types everywhere. Column definitions must use the same TData as the data passed to useTable.data needs a stable reference. A new array identity every render (data={rawApiResponse.map(...)} inline) defeats memoization and forces the whole table to recompute — keep it in module scope, useState, useMemo, or a query cache (e.g. TanStack Query), never recreated inline on every render.accessorKey (accessorKey: 'name.first') to reach nested fields, or use accessorFn: (row) => row.info.age for anything an accessor path can't express. A literal period inside a key name breaks accessorKey path parsing — use accessorFn for those keys instead.subRows?: Array<TData> field (any name, configurable) on each row object is what the Expanding feature walks to build nested rows — no separate tree data structure needed.Record<string, unknown>) rather than forcing a nominal type, and build columns dynamically from the data's actual keys at runtime.type User = { firstName: string; lastName: string; subRows?: User[] }
// stable reference — module scope, state, or a query result, never inline
const data: User[] = []
const columns: ColumnDef<typeof features, User>[] = [
{ header: 'First', accessorKey: 'firstName' },
{ header: 'Nested', accessorKey: 'address.city' }, // dot-path
{ header: 'Computed', accessorFn: (row) => `${row.firstName} ${row.lastName}`, id: 'fullName' },
]
User type that also declares optional subRows for expansion.TData right first — every column/row/cell type error traces back to a mismatched or unstable data type.data array inline in the render body; that alone causes most "table re-renders/recomputes constantly" bugs.accessorFn whenever an accessorKey dot-path can't express the access (computed values, keys with literal periods, deeply conditional lookups).subRows to your data type — no separate tree-building step.accessorKey/accessorFn/id contract this chapter previews.subRows becomes expandable UI.