Skip to content

fix(jobs): pass useRef an explicit initial value - #35

Merged
umutcankurt merged 1 commit into
mainfrom
fix/useref-explicit-initial-value
Jul 29, 2026
Merged

fix(jobs): pass useRef an explicit initial value#35
umutcankurt merged 1 commit into
mainfrom
fix/useref-explicit-initial-value

Conversation

@umutcankurt

Copy link
Copy Markdown
Owner

One line of code, but it removes the wall that has been hiding what the React 19
upgrade (#15) actually involves.

The problem

React 19 removed useRef's zero-argument overload, so this fails against its types:

src/pages/JobHistory.tsx(30,32): error TS2554: Expected 1 arguments, but got 0

It is the only argument-less useRef in the codebase — 1 of 8 call sites —
and CI on #15 stops there, at the type-check step, before the tests or the
build ever run
. So nobody knew what was behind it.

The change is React 18-safe

Not a forward-port that breaks the present. React 18's third overload is:

function useRef<T = undefined>(initialValue?: undefined): MutableRefObject<T | undefined>;

Passing undefined explicitly resolves to that same overload, so the ref keeps
its exact type. Verified rather than assumed — a scratch probe asserting mutual
assignability between the old and new forms type-checked clean against the
installed React 18 types:

const before = useRef<ReturnType<typeof setTimeout>>();
const after  = useRef<ReturnType<typeof setTimeout>>(undefined);
const _a: typeof before = after;   // ✅
const _b: typeof after = before;   // ✅

What is behind the wall — measured

With this fix applied, React 19.2.8 + @types/react 19.2.17 installed locally
as a throwaway experiment (reverted afterwards; this PR does not bump React):

gate result under React 19
tsc --noEmit 0 errors
npm run lint (+3 postlint gates) pass
npx vitest run 458 tests / 34 files pass
npx vite build pass

Also swept for the APIs React 19 removed, since green gates do not prove runtime
behaviour:

removed / changed in 19 occurrences
ReactDOM.render / hydrate 0
findDOMNode 0
string refs (ref="name") 0
defaultProps on function components 0
propTypes 0
legacy context (childContextTypes) 0
react-test-renderer 0
unmountComponentAtNode 0

The entry point already uses createRoot. forwardRef appears 12 times and is
deprecated-but-supported in 19, so it is cleanup, not a blocker.

Caveat worth stating plainly: all of the above is static and test-level. It
says the React 19 migration is far smaller than feared, not that it is risk-free
— StrictMode and effect-timing changes are exactly the kind of thing this
project's 34 test files would not catch. React 19 still deserves its own PR with
a manual pass over the app.

Verification of this PR itself (React 18, unchanged)

npm run lint, npx tsc --noEmit, npm run i18n:check, npx vitest run
(458 tests / 34 files), npx vite build — all pass.

🤖 Generated with Claude Code

React 19 removed useRef's zero-argument overload, so
`useRef<ReturnType<typeof setTimeout>>()` fails to compile against its types:

    src/pages/JobHistory.tsx(30,32): error TS2554: Expected 1 arguments, but got 0

This is the only argument-less useRef in the codebase — 1 of 8 call sites — and
it is what stops CI on the React 19 upgrade PR (#15) at the type-check step,
before the tests or the build ever run. Fixing it here means that PR's real
surface becomes visible instead of everyone stopping at the same known error.

The change is React 18-safe, not a forward-port that breaks the present: React
18's third overload is `useRef<T = undefined>(initialValue?: undefined)`, so
passing `undefined` explicitly resolves to that same overload and the ref keeps
its `MutableRefObject<ReturnType<typeof setTimeout> | undefined>` type. Verified
rather than assumed — a scratch probe asserting mutual assignability between the
old and new forms type-checked clean under the installed React 18 types.

Verified: lint, tsc --noEmit, i18n:check, 458 tests / 34 files, vite build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@umutcankurt
umutcankurt merged commit 915f6a9 into main Jul 29, 2026
4 checks passed
@umutcankurt
umutcankurt deleted the fix/useref-explicit-initial-value branch July 29, 2026 11:20
umutcankurt added a commit that referenced this pull request Jul 29, 2026
Turns the [Unreleased] section into 0.8.1 and fills the three gaps today's
merges left in it.

#33 shipped the README toolchain refresh, #34 the brace-expansion lockfile
patch and #35 the useRef fix, but none of the three wrote itself into the
changelog. The dependency-modernisation entries that #33 did add are
unchanged.

A new Security section records both the alert #8 fix and the two advisories
that were assessed and deliberately left alone: brace-expansion
CVE-2026-14257, whose only patched release is 5.0.8 while its vulnerable
range still covers the already-backported 1.x and 2.x maintenance lines,
and react-router GHSA-qwww-vcr4-c8h2, which the advisory itself scopes to
the unstable RSC APIs this app does not use. Recorded rather than patched
because npm's own remedy for the first is a downgrade of
eslint-plugin-jsx-a11y and the second's is a major.

Also defines the [0.7.9] and [0.8.0] link references, which were never
added, and repoints [Unreleased] from v0.7.8 to v0.8.1.

Verified: lint + postlint, tsc --noEmit, i18n:check, 458 tests / 34 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant