Rules Hub

Coding Rules Library

← Back to all rules
fullstack ruleStack: typescript
typescriptgenericstype-safetyapi

Prefer intermediate unknown cast for diverging generics

Cast raw data to unknown before asserting specific generic types to handle diverging type paths safely.

PR: Feat/FCK-2245 - Cache Bellsheep and profile loaders with TanStack Query #343Created: Dec 10, 2025

Bad example

Old codets
1async function fetchApi<TData, TResult = TData>(
2 url: string,
3 transform?: (data: TData) => TResult
4): Promise<TResult> {
5 const response = await fetch(url);
6
7 // Direct cast forces TData, making it hard to return TResult later
8 // without ugly double casting (as unknown as TResult).
9 const data = await response.json() as TData;
10
11 if (transform) {
12 return transform(data);
13 }
14
15 // TypeScript error: Type 'TData' is not assignable to type 'TResult'.
16 // 'TResult' could be instantiated with an arbitrary type which could be unrelated to 'TData'.
17 return data;
18}

Explanation (EN)

Directly casting the response to `TData` assumes the raw shape matches the input type. This causes type conflicts when the function needs to return `TResult` (which might differ from `TData`), forcing unsafe double assertions later.

Objašnjenje (HR)

Izravno castanje odgovora u `TData` pretpostavlja da sirovi oblik odgovara ulaznom tipu. To uzrokuje konflikte tipova kada funkcija treba vratiti `TResult` (koji se može razlikovati od `TData`), što prisiljava na nesigurne dvostruke promjene tipova kasnije.

Good example

New codets
1async function fetchApi<TData, TResult = TData>(
2 url: string,
3 transform?: (data: TData) => TResult
4): Promise<TResult> {
5 const response = await fetch(url);
6
7 // Cast to unknown first to explicitly reset type assumptions.
8 // This allows clean assertion to either TData or TResult based on logic flow.
9 const rawData = await response.json() as unknown;
10
11 if (transform) {
12 return transform(rawData as TData);
13 }
14
15 return rawData as TResult;
16}

Explanation (EN)

Casting `json()` to `unknown` first acknowledges that the runtime type is uncontrolled. It acts as a neutral intermediate step, allowing the code to cleanly assert `as TData` for transformation or `as TResult` for the final return value without satisfying incorrect overlaps.

Objašnjenje (HR)

Castanje `json()` prvo u `unknown` potvrđuje da je runtime tip nekontroliran. Djeluje kao neutralni međukorak, omogućujući čisto tvrđenje `as TData` za transformaciju ili `as TResult` za konačnu povratnu vrijednost bez zadovoljavanja netočnih preklapanja.