TypeScript
The starter's tsconfig.json sets:
| Option | Why |
|---|---|
"jsx": "react-jsx" |
TSX compiles to react/jsx-runtime, a shared module; no file imports React for JSX |
"moduleResolution": "bundler" |
imports resolve as Vite resolves them; relative imports need no .js |
"strict": true |
null checks and the other strict checks |
"isolatedModules": true |
Vite compiles each file on its own; re-export a type with export type |
"skipLibCheck": true |
the packages' declarations are not checked again |
"lib": ["ES2022", "DOM", "DOM.Iterable"] |
the browser's APIs |
The types come with the packages: BladeProps, PropertyEditorProps, CmsApi, NodeData and the
rest from @relatude/sdk, component props from @relatude/ui, and React's from @types/react.
Vite strips types without checking them, so a type error never stops npm run dev or
npm run build. Your editor marks errors as you type; run npm run typecheck before you build.
To read the site's content with types, describe the C# model's types by their CodeNames, with only
the properties the plugin reads. A decimal is db.Decimal, and a relation end is db.One<T> or
db.Many<T> (chapter 19):
import { useEffect, useState } from 'react';
import { db, useCms } from '@relatude/sdk';
interface IProductPage { Name: string; Price: db.Decimal; Stock: number }
const Product = db.nodeType<IProductPage>('IProductPage');
export function LowStock() {
const { store } = useCms();
const [rows, setRows] = useState<db.Node<IProductPage>[]>([]);
useEffect(() => {
store?.query(Product)
.where(p => p.Stock.lt(5))
.orderBy(p => p.Name)
.page(0, 20)
.execute()
.then(result => setRows(result.items));
}, [store]);
return <ul>{rows.map(r => <li key={r.$id}>{r.Name}: {r.Stock}</li>)}</ul>;
}The field handles are typed, so p.Stock.startsWith('a') does not compile, and a misspelt property
is an error in your editor rather than in the query. store is null in the offline demo (?demo).