Rules Hub

Coding Rules Library

← Back to all rules
fullstack ruleStack: typescript
typescriptgenericstype-assertionclean-codeapi

Align I/O type assertions with return generics

When parsing external data in generic functions, cast directly to the return type generic to avoid type mismatches or suppressed errors.

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

Bad example

Old codets
1async function fetchApi<TOut, TIn = TOut>(
2 url: string,
3 transform?: (data: TIn) => TOut
4): Promise<TOut> {
5 const response = await fetch(url);
6
7 // Bad: Casting to input type TIn causes errors when returning as TOut,
8 // often leading developers to use @ts-expect-error to silence it.
9 // @ts-expect-error
10 const data = (await response.json()) as TIn;
11
12 if (transform) return transform(data);
13 return data; // Error: TIn is not assignable to TOut
14}

Explanation (EN)

Casting the raw response to the input type (`TIn`) creates a type conflict when the function needs to return the output type (`TOut`) in the absence of a transformer. This forces developers to suppress errors, hiding potential issues.

Objašnjenje (HR)

Castanje sirovog odgovora u ulazni tip (`TIn`) stvara konflikt tipova kada funkcija mora vratiti izlazni tip (`TOut`) u slučaju da nema transformatora. To prisiljava programere na suzbijanje grešaka, što skriva potencijalne probleme.

Good example

New codets
1async function fetchApi<TOut, TIn = TOut>(
2 url: string,
3 transform?: (data: TIn) => TOut
4): Promise<TOut> {
5 const response = await fetch(url);
6 const rawData = await response.json();
7
8 // Good: Cast explicitly to the return type TOut for the default case.
9 // This acknowledges that at the I/O boundary, we are asserting the shape.
10 const data = rawData as TOut;
11
12 if (transform) {
13 // Cast to TIn only specifically when passing to the transformer
14 return transform(rawData as TIn);
15 }
16 return data;
17}

Explanation (EN)

By casting the raw data directly to the return type (`TOut`), we satisfy the function's contract without type errors. We only cast to the input type (`TIn`) strictly when invoking the transform function, keeping assertions clean and logical.

Objašnjenje (HR)

Izravnim castanjem sirovih podataka u povratni tip (`TOut`) zadovoljavamo ugovor funkcije bez grešaka u tipovima. U ulazni tip (`TIn`) castamo samo onda kada pozivamo funkciju transformacije, čime održavamo asercije čistima i logičnima.