refactor(backend): type the admin item queries, and fix the stale status union (#159)
admin.ts has no untyped reads left. Typed sites go from 43 to 49. New ItemRecord in itemSelect.ts for the bare `items` row that `RETURNING *` gives back. Deliberately not AdminItemRow: that describes a select which joins the category and adds images and tags as subqueries, so typing a RETURNING * as it would promise three fields the result does not contain. Three shapes for one table, because three different queries return three different things. The typing found a real defect on its first run, which is the case for doing this at all. `ItemStatus` in types.ts was `'available' | 'reserved' | 'sold'`. The database has four values and defaults to 'pending' — items have arrived pending since #90. itemFilters.ts declared its own copy that had all four and was correct. Two declarations of one union with nothing connecting them: one went stale and nothing said so. It was invisible while query rows were `any`. Typing them turned `if (status === 'pending')` in admin.ts into TS2367, "this comparison appears to be unintentional because the types 'ItemStatus' and '\"pending\"' have no overlap" — a compiler telling us the unpublish route's guard could never be true, against a type that was simply wrong. Confirmed against the database rather than by picking the more plausible of the two declarations: `SELECT DISTINCT status FROM items` returns pending, available, reserved and sold. Fixed by removing the duplication rather than by patching both copies. types.ts now holds the only declaration and itemFilters.ts imports it, re-exporting so its existing importers are unaffected. Patching both would have left the next drift free to happen the same way. Verified: tsc clean, unit 254/254, integration 238/238, and backend lint unchanged — the four warnings it reports are identical to those on main with these changes stashed, so none of them are new. Refs #159
This commit is contained in:
+13
-1
@@ -1,4 +1,16 @@
|
||||
export type ItemStatus = 'available' | 'reserved' | 'sold';
|
||||
/**
|
||||
* Every value `items.status` can hold.
|
||||
*
|
||||
* 'pending' was missing here from the moment items started arriving pending,
|
||||
* while itemFilters.ts declared its own copy that had it. Two declarations of
|
||||
* one union is how that happens: nothing connects them, so one goes stale and
|
||||
* nothing says so. The stale one was harmless only because query rows were
|
||||
* `any` — typing them turned `status === 'pending'` in admin.ts into a compile
|
||||
* error about a comparison with no overlap, which is how it was found.
|
||||
*
|
||||
* This is now the single declaration. itemFilters.ts imports it.
|
||||
*/
|
||||
export type ItemStatus = 'pending' | 'available' | 'reserved' | 'sold';
|
||||
|
||||
export interface ItemImage {
|
||||
id: number;
|
||||
|
||||
Reference in New Issue
Block a user