Prevent undefined/void/falsy values from becoming accidental runtime states.
Apply these rules:
undefined: If a value can be absent (e.g., localStorage, optional query data), wire an explicit defaultValue so hooks/state initialize to a concrete value and consumers never render an “undefined first frame”.
useState initial value from defaultValue inside the utility hook rather than letting it be undefined and patching later.window/DOM.void/no-arg and falsy as testable cases: When designing/using optional variables or cached data, add type and runtime tests for void (no variables) and for falsy cached values (e.g., '', 0, false) so “absent” isn’t conflated with “no result”.undefined being “missing” during key/hash matching: If keys are serialized/hashed (e.g., via JSON.stringify) or displayed via hashes, undefined may be removed, making different logical keys collide or fail to match.
Example (default to avoid initial undefined):
function useLocalStorage<T>(key: string, defaultValue: T) {
const [value, setValue] = React.useState<T>(() => {
const raw = localStorage.getItem(key)
return raw == null ? defaultValue : (JSON.parse(raw) as T)
})
// ...sync back to localStorage
return [value, setValue] as const
}
If a behavior constraint exists (e.g., a function must not return undefined), encode it in types and tests—don’t “test” impossible states.
Enter the URL of a public GitHub repository