Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Validate external responses instead of casting to a generic type
Don't cast fetched data to a caller-supplied <T>; return unknown and validate the shape at the call site with a schema.
Bad example
| 1 | export async function request<T>(args: RequestArgs): Promise<T> { |
| 2 | const res = await fetch(url, options); |
| 3 | if (!res.ok) throw new Error(`Failed: ${res.status}`); |
| 4 | return res.json() as Promise<T>; // unchecked cast — lies about safety |
| 5 | } |
| 6 |
|
| 7 | const user = await request<User>(args); // could be anything at runtime |
Explanation (EN)
The generic <T> is a lie: the function never verifies the payload matches T, so a malformed response is typed as valid and blows up later, far from the source.
Objašnjenje (HR)
Genericki <T> je laz: funkcija nikad ne provjerava odgovara li payload tipu T, pa se neispravan odgovor tipizira kao valjan i pukne kasnije, daleko od izvora.
Good example
| 1 | export async function request(args: RequestArgs): Promise<unknown> { |
| 2 | const res = await fetch(url, options); |
| 3 | if (!res.ok) throw new Error(`Failed: ${res.status}`); |
| 4 | return res.json() as Promise<unknown>; |
| 5 | } |
| 6 |
|
| 7 | // At the call site, validate against a schema you control: |
| 8 | const user = parse(UserSchema, await request(args)); // throws if shape is wrong |
Explanation (EN)
Returning unknown forces callers to validate against a schema (e.g. Valibot/Zod) where the expected shape is actually known, so the types reflect a real runtime check.
Objašnjenje (HR)
Vracanje unknown tjera pozivatelje da validiraju prema shemi (npr. Valibot/Zod) gdje je ocekivani oblik stvarno poznat, pa tipovi odrazavaju stvarnu provjeru u runtimeu.
Notes (EN)
Prefer a lightweight schema library (Valibot is much smaller than Zod) for runtime validation of untrusted I/O boundaries.
Bilješke (HR)
Za runtime validaciju nepouzdanih I/O granica preferiraj laganu schema biblioteku (Valibot je puno manji od Zoda).
Exceptions / Tradeoffs (EN)
Balance against align-generic-type-assertions: at a true external/untrusted boundary, return unknown and runtime-validate rather than cast to the generic. Balance against prefer-intermediate-unknown-cast-for-generics: for untrusted external data, runtime-validate instead of casting through unknown to the target type.