Skip to main content

Nullable state

Dealing with nullable state

If a state can be missing (e.g. nested property is undefined) or null, checking for null state value is essential before diving into the nested states.

Typescript will fail a compilation if you attempt to work with nested states of a state, which might have null/undefined state value. For example:

interface Task { name: string, priority?: number }

const MyComponent = () => {
const state = useHookstate<Task | null>(null)

// JS - runtime error, TS - compilation error
state.name.value
// JS - runtime error, TS - compilation error
state.value.name
}

Here is the recommended way to check for null/undefined before unfolding nested states:

// type is for clarity, it is inferred by the compiler
const stateOrNull: State<Task> | null = state.ornull
if (stateOrNull) {
// neither compilation nor runtime errors
stateOrNull.name.value

// neither compilation nor runtime errors
stateOrNull.value.name
}

State.ornull property is a very convenient way to deal in those cases. Here is an example of a component, which receives a state whose value might be null.

const MyInputField = (props: { state: State<string | null>}) => {
const state: State<string> | null = props.state.ornull;
// state is either null or an instance of State<string>:
if (!state) {
// state value was null, do not render form field
return <></>;
}
// state value is an instance of string, can not be null here:
return <input value={state.value} onChange={(v) => state.set(v.target.value)} />
}

State.ornull property is just a convenience. Traditional || may also work depending on a case. Here is an example of a component, which receives a state whose value might be null, but still proceeds with rendering 'state editor':

const MyInputField = (props: { state: State<string | null>}) => {
// state value is an instance of string or null here:
return <input value={state.value || 'my default'} onChange={(v) => state.set(v.target.value)} />
}