Skip to content

TypeScript

Sygnal ships with full TypeScript type definitions. Use the Component and RootComponent types for type safety:

import type { Component, RootComponent } from 'sygnal'
// Define your types
type AppState = {
count: number
name: string
}
type AppActions = {
INCREMENT: null
SET_NAME: string
}
// Type the component
const App: RootComponent<AppState, {}, AppActions> = ({ state }) => {
return (
<div>
<h1>{state.name}: {state.count}</h1>
</div>
)
}
App.initialState = { count: 0, name: 'Counter' }
App.intent = ({ DOM }) => ({
INCREMENT: DOM.select('.btn').events('click'),
SET_NAME: DOM.input('.input').value()
})
App.model = {
INCREMENT: (state) => ({ ...state, count: state.count + 1 }),
SET_NAME: (state, data) => ({ ...state, name: data })
}
export default App
Component<STATE, PROPS, DRIVERS, ACTIONS, CALCULATED, CONTEXT, SINK_RETURNS>
ParameterDescription
STATEShape of the component’s state
PROPSShape of props received from parent
DRIVERSCustom driver type specifications
ACTIONSMap of action names to their data types
CALCULATEDShape of calculated field values
CONTEXTShape of context values
SINK_RETURNSReturn types for non-state sinks
import type { Component } from 'sygnal'
type Tile = {
id: number
row: number
column: number
value: number
new?: boolean
deleted?: boolean
}
type TileActions = {
DELETE: null
}
const TILE: Component<Tile, any, any, TileActions> = (_props, state) => {
return (
<div className="tile" id={`tile-${state.id}`}>
{state.value}
</div>
)
}

Use exactState() to enforce that state updates match your type exactly (no extra properties):

import { exactState } from 'sygnal'
import type { AppState } from './types'
const asAppState = exactState<AppState>()
App.model = {
UPDATE: (state) => asAppState({ ...state, count: state.count + 1 })
// TypeScript error if you add properties not in AppState
}