Two any[] and a leaderboard that lied about its own shape
Flag/Not Flag's frontend held its leaderboard in useState<any[]>([]). Every entry that came back from /api/leaderboard - score, time, player name - passed through untyped, all the way into a sort comparator that also took (a: any, b: any). The most visible data on the results screen had no type checking on it at all.
A sibling surface, the dashboard, already had the type that looked like the obvious fix: a LeaderboardEntry interface with id, player_name, score, time_taken, mode, created_at, all required. Copy it into the frontend, wire it in, done.
It didn't fit. The frontend's leaderboard doesn't read from where the dashboard's does - it goes through a Cloudflare D1-backed endpoint that never selects an id column and only sets created_at at insert time, not on read. A LeaderboardEntry with id and created_at marked required would have been wrong the moment it shipped: the real return type of fetchTopScores doesn't have those fields on the way out. So the frontend's version makes both optional - a small deviation from the dashboard's interface, made because copying it verbatim would have produced a type that lied about its own shape.
With that settled, the rest was mechanical: the useState call took the real type, the sort comparator's parameters resolved on their own once the state feeding it was typed, and two catch (err: any) blocks along the same save/fetch path became catch (err: unknown) with an instanceof Error check. tsc --noEmit and the test suite both pass now.
The interesting part isn't the typing - it's that two surfaces reading "the same" leaderboard data didn't actually share a shape, and nobody had caught it until something forced a look at both at once.