Skip to content

Typed tables

matter extension types writes matter-extension.d.ts, or the path that types in matter.json names. It holds one entry for each table in the extension’s space, generated from the tables as they are in Matter now, and adds them to the Tables of @matter.work/extension-sdk, the SDK’s types. Include the file in your tsconfig.json.

matter.table('Deals') is then typed, and the compiler catches what the data API would refuse at run time:

  • a table, index or field that doesn’t exist;
  • an eq that’s missing one of the index’s match fields, or names an option the field doesn’t have;
  • a range on anything but the index’s first order field, or with the wrong type of value;
  • a sort or filter on a field that doesn’t exist;
  • groupCount by a field that isn’t one of the index’s match fields;
  • upsert on an index that isn’t unique;
  • write values of the wrong type, or several people for a field that holds one.

Rows come back typed. row.values.Stage is 'Lead' | 'Won' | …, and fields that may be empty are optional. Option names in row values also accept any string, since someone may add an option in Matter after you generated the types. Writes, eq and filters accept only the options the field has, unless a write passes { createOptions: true } to add the ones it names (see Options).

Without generated types, every table is untyped.

  • matter extension dev regenerates the file whenever the space’s tables change while it runs, so a field added in Matter is in your types seconds later.
  • matter extension deploy warns when the file is out of date.
  • Otherwise, run matter extension types again after changing tables.

Don’t edit the file: it’s rewritten each time.

The SDK’s package exports what you need to write typed helpers, such as React hooks:

Type What it is
Tables Every table of the space, by name.
TableRead<T> Any read of a table: through one of its indexes, with that index’s own checks, or a scan.
TableMatch<T> Rows matching any of a table’s indexes, for count, exists and ids.
TableGroupRead<T> A groupCount through any of a table’s indexes.
TypedGroups<T, I> What groupCount gives through index I.
Row<Values> A row with these values.
Person, LinkedRow, Attachment The shapes of those values.
import type { Row, TableRead, Tables } from '@matter.work/extension-sdk'
type TableName = keyof Tables & string
declare function useQuery<N extends TableName>(
table: N,
read: TableRead<Tables[N]> | null,
): Row<Tables[N]['values']>[]
const LEADS: TableRead<Tables['Deals']> = { index: 'by_stage', eq: { Stage: 'Lead' } }

A worker, tools or run server in TypeScript import @matter.work/extension-sdk as pages do, and the same file types their tables: include it in the tsconfig.json that compiles them.