Skip to content

Storage hooks type value as T | undefined when initializeWithValue is unset #1697

Description

@xobotyi

Prior Issues

#1002 reported the same default on the runtime side and was fixed in
17.0.1. The result type was never updated to match, and has had its current shape since v17.0.0
(7bcc385).

What is the current behavior?

useLocalStorageValue and useSessionStorageValue type value as Type | undefined even when initializeWithValue
is left at its documented default of true — that is, when the hook does read the storage during the first render and
can never hand back undefined.

Every call site is forced into a null check or a non-null assertion that cannot fire.

Steps to Reproduce

  1. npm install @react-hookz/web@26.1.0 react@19 react-dom@19 @types/react@19 typescript@5.9
  2. Use tsconfig.json with "strict": true, "module": "NodeNext", "moduleResolution": "NodeNext",
    "lib": ["ESNext", "DOM"]
  3. Create repro.ts:
import {useSessionStorageValue, useLocalStorageValue} from '@react-hookz/web';

// A `defaultValue` is set and `initializeWithValue` is left at its default.
export function useName(): string {
	const {value} = useSessionStorageValue('name', {defaultValue: 'anonymous'});
	return value;
}

// No options at all, `Type` given explicitly.
export function useToken(): string {
	return useLocalStorageValue<string>('token').value;
}
  1. Run tsc --noEmit

Reproducible at will. Both calls fail:

repro.ts(6,2): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
  Type 'undefined' is not assignable to type 'string'.
repro.ts(11,2): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
  Type 'undefined' is not assignable to type 'string'.

The runtime disagrees with both: src/useStorageValue/index.dom.test.ts already asserts that the first render carries
the stored value unless initializeWithValue: false is passed.

What is the expected behavior?

value is string in both cases. undefined belongs in the type only when the first read is actually deferred —
{initializeWithValue: false}, or a flag whose value is not known at compile time.

Environment Details

  • @react-hookz/web version: 26.1.0
  • react version: 19.2
  • react-dom version: 19.2
  • typescript version: 5.9 (also reproduced with 7.0.2)
  • OS: macOS (darwin 25.5.0)
  • Browser: n/a, type-level only
  • Did this work in previous versions? No. Present since v17.0.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    🪲 bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions