Skip to content

TypeScript

witqq spreadsheet is built with TypeScript and provides full generic type inference for row data, columns, events, and refs.

The WitTable component accepts a generic type parameter TRow that represents your row data shape:

interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
category: string;
}
<WitTable<Product>
columns={columns}
data={products}
editable={true}
/>

This ensures that data must be an array of Product objects and that column key values correspond to fields on Product.

Use satisfies to get autocomplete while keeping the array type compatible:

import type { ColumnDef } from '@witqq/spreadsheet';
const columns = [
{ key: 'id', title: 'ID', width: 60, type: 'number' as const },
{ key: 'name', title: 'Product', width: 200, type: 'string' as const },
{ key: 'price', title: 'Price', width: 100, type: 'number' as const },
{ key: 'inStock', title: 'In Stock', width: 80, type: 'boolean' as const },
{ key: 'category', title: 'Category', width: 150, type: 'string' as const },
] satisfies ColumnDef[];

Event callbacks receive typed parameters:

<WitTable<Product>
columns={columns}
data={products}
editable={true}
onCellChange={(event: CellChangeEvent) => {
console.log(`Row ${event.row}, Col ${event.col}: ${event.oldValue}${event.newValue}`);
}}
onSelectionChange={(event: SelectionChangeEvent) => {
console.log('Active cell:', event.selection.activeCell);
console.log('Ranges:', event.selection.ranges);
}}
onSortChange={(event: SortChangeEvent) => {
console.log('Sort changed:', event);
}}
onFilterChange={(event: FilterChangeEvent) => {
console.log('Active filters:', event);
}}
/>

Use WitTableRef to get type-safe access to imperative methods:

import { useRef } from 'react';
import type { WitTableRef } from '@witqq/spreadsheet-react';
function ProductTable() {
const tableRef = useRef<WitTableRef>(null);
const selectFirstCell = () => {
tableRef.current?.selectCell(0, 0);
};
const readCell = () => {
const value = tableRef.current?.getCell(0, 0);
console.log('Cell [0,0]:', value);
};
const updateCell = () => {
tableRef.current?.setCell(0, 1, 'Updated Name');
};
return <WitTable<Product> ref={tableRef} columns={columns} data={products} />;
}

All methods available on the ref:

interface WitTableRef {
getInstance(): WitEngine; // Access underlying engine
focus(): void; // Focus the table canvas
getSelection(): Selection; // Current selection state
selectCell(row: number, col: number): void;
getCell(row: number, col: number): unknown;
setCell(row: number, col: number, value: unknown): void;
undo(): void;
redo(): void;
scrollTo(x: number, y: number): void;
requestRender(): void; // Force re-render
installPlugin(plugin: WitPlugin): void;
removePlugin(name: string): void;
print(): void; // Trigger print view
}

When working with the engine directly, cell values are typed through the CellData interface:

import type { CellData } from '@witqq/spreadsheet';
const engine = tableRef.current?.getInstance();
if (engine) {
const cell: CellData | undefined = engine.getCellStore().get(0, 0);
if (cell) {
console.log(cell.value); // CellValue (string | number | boolean | Date | null)
console.log(cell.displayValue); // Formatted string for rendering
console.log(cell.type); // CellType
}
}