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
39 lines
1.1 KiB
TypeScript
Executable File
39 lines
1.1 KiB
TypeScript
Executable File
/**
|
|
* 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;
|
|
image_path: string;
|
|
sort_order: number;
|
|
}
|
|
|
|
export interface ItemTag {
|
|
id: number;
|
|
name: string;
|
|
color: string;
|
|
}
|
|
|
|
export interface Item {
|
|
id: number;
|
|
name: string;
|
|
description: string | null;
|
|
price_cents: number;
|
|
images: ItemImage[];
|
|
status: ItemStatus;
|
|
reserved_until: string | null;
|
|
sold_at: string | null;
|
|
paypal_order_id: string | null;
|
|
created_at: string;
|
|
}
|