React Compiler + Turbopack: lazy useState initializer throws TDZ when helper function declarations appear later in the same hook
Link to the code that reproduces this issue
https://github.com/michaltarasiuk/usestate-tdz-repro
To Reproduce
To Reproduce
- Clone https://github.com/michaltarasiuk/usestate-tdz-repro
- Run
bun install - Confirm
next.config.tshasreactCompiler: trueandexperimental.turbopackRustReactCompiler: true - Run
bun dev(Turbopack is the default in Next.js 16) - Open http://localhost:3000
Expected: the page renders and shows Stored value: default.
Actual: Next.js shows a runtime error overlay:
Runtime ReferenceError
Cannot access 'parseItem' before initialization
The broken hook is hooks/use-local-storage-broken.ts. It calls useState(getItem) before function parseItem is declared in the same hook. That is valid JavaScript (nested function declarations hoist), but React Compiler lowers parseItem to a const while leaving useState(getItem) above it.
Note: the error does not reproduce without React Compiler. With reactCompiler disabled, the page works and shows Stored value: default. After changing next.config.ts, restart with rm -rf .next && bun dev.
Current vs. Expected behavior
Expected: the hook runs on the client and the page renders with Stored value: default. In plain JavaScript, nested function declarations hoist within the hook body, so this is valid:
const [item, setItem] = useState(getItem);
function parseItem(stored: string | null) { … }
function getItem() {
return parseItem(localStorage.getItem(key));
}
When useState runs the lazy initializer, getItem can call parseItem because both are hoisted.
Actual: with reactCompiler: true and experimental.turbopackRustReactCompiler: true, the client bundle throws:
Runtime ReferenceError
Cannot access 'parseItem' before initialization
at getItem (hooks/use-local-storage-broken.ts:…)
React Compiler lowers parseItem to a const but leaves useState(getItem) above it. The lazy initializer runs before parseItem is assigned, so getItem hits a temporal dead zone.
Compiled output (simplified from .next/dev/static/chunks/…):
const [item, setItem] = useState(getItem);
// …
const parseItem = t4;
function getItem() {
return parseItem(localStorage.getItem(key));
}
Without React Compiler, the same source works. Turbopack alone is not enough to trigger this; the compiler transform is the difference.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.6.0
Binaries:
Node: 24.3.0
npm: 11.6.2
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 16.3.5
eslint-config-next: N/A
react: 19.2.8
react-dom: 19.2.8
typescript: 5.9.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Turbopack, SWC
Which stage(s) are affected? (Select all that apply)
next dev (local)
Additional context
No response
Source: vercel/next.js