Rules Hub
Coding Rules Library
Prefer intermediate unknown cast for diverging generics
Cast raw data to unknown before asserting specific generic types to handle diverging type paths safely.
Bad example
| 1 | async 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
| 1 | async 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.