B2: TypeScript + React 19 migration (T1–B18) #87
No reviewers
Labels
No Label
architecture
backend
bug
feature
frontend
priority:critical
priority:high
priority:low
priority:medium
priority:nice-to-have
ux
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: null/BillTracker#87
Loading…
Reference in New Issue
No description provided.
Delete Branch "branch/b2-typescript"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Batch 2 of 3. Stacked on
branch/b1-react-query(B1).66 commits:
907a407): TypeScript foundation — tsconfig + typecheck in CI255036a): Branded Cents/Dollars money types7d9bf12): docs entry for the TS foundationb221e02…d02d3c9): utils, usePaymentActions, trackerUtils, lib utilities, small hooks + version, API client, React Query hooks.jsx→.tsx/.ts(UI primitives → app shell → bill-modal → admin/ → data/ → final pages).ts/.tsxWorth flagging on the PR:
Cents/Dollarsbranded types — the guard test (money.type-test.ts) uses@ts-expect-errorso a regression in the branding failstsc..tsx-only classes were producing no CSS.bb3e9f5) lists the real defects the TS migration caught: deadcacheTimeconfig (silent in v5), narrowing bug in un-pay Undo, missingCountPillimport that would have crashed a live CSV preview, deadtotalstate on Spending, etc.Converted client/lib/money.js -> money.ts with branded types: type Cents = number & { __unit: 'cents' } type Dollars = number & { __unit: 'dollars' } plus asCents/asDollars/centsToDollars/dollarsToCents. The formatters now require the correct branded unit (a bare number won't do), so a typed caller physically cannot format cents as dollars (the 100×-too-big bug) or vice-versa. Existing .jsx callers are unaffected (checkJs off) — gradual adoption. money.type-test.ts is a compile-time guard (never imported/bundled): its @ts-expect-error lines assert each unit mixup is a real error, so typecheck fails loudly if the branding ever regresses. Verified: removing a guard makes tsc error 'Argument of type 1234 is not assignable to DollarsInput'. typecheck + build (with React Compiler) + 48 client tests all green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>New client/types.ts domain-types module. Types the full /tracker response — TrackerResponse { summary, bank_tracking, cashflow, rows } — with every money field branded `Dollars` (the server serializes cents→dollars, verified against statusService.buildTrackerRow + trackerService.getTracker + buildBankTracking + buildSafeToSpend). api.tracker() now returns Promise<TrackerResponse>. TrackerRow + TrackerStatus move to @/types (canonical) and are re-exported from @/lib/trackerUtils for compat; trackerUtils' row money fields upgrade from plain `number` to branded `Dollars` (rowThreshold -> Dollars, paymentSummary re-brands its computed amounts via asDollars so callers can fmt() them directly). This is the first endpoint where the money brand flows end-to-end: fetch layer -> row helpers, and (in phase B) into the components that format them. Nested payloads no typed consumer reads yet (summary.trend, autopay_suggestion/ _stats, sparkline) are left `unknown`, to refine when consumed. asDollars is an identity at runtime, so behavior is unchanged: typecheck 0, lint 0 errors, build green, 48 client tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Root cause of the B2 e2e regression: tailwind's `content` was `./client/**/*.{js,jsx}`, so once a component became .tsx, Tailwind stopped scanning it and never generated CSS for any class used *only* there. The release-notes dialog broke because its `left-[50%] top-[50%]` centering classes (unique to the now-.tsx dialog) produced no CSS — the modal rendered off-screen (transform applied, but `left/top` were 0/2359px), covering the tracker so the auth-setup probe couldn't reach "Add Bill". Fix: include `ts,tsx` in the content globs. Verified via computed style — the dialog is centered again (left:640px top:360px, on-screen) and the 17/17 e2e probe passes. This should have shipped with the TS foundation (T1); it silently affected every .tsx conversion (they only looked fine because their classes also appeared in some .jsx file). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>The living QA doc's copy-pasteable coverage-recon greps pointed at client/App.jsx, Sidebar.jsx, <Page>.jsx and the B-UI primitive census listed button.jsx/input.jsx/etc — all now .tsx, so the commands errored ('No such file'). Retargeted to .tsx (+ useAutoSave.test.ts) and noted that recon greps target .tsx and 'npm run typecheck' is now a guard. Behavior-only migration: client 42/42 + e2e probe 17/17 stay green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Pull request closed