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).
A type guard must check every field that distinguishes the narrowed variant
When a type predicate narrows a union to one variant, verify all the fields that variant guarantees, not just one of them.
Bad example
| 1 | type ShippedOrder = { orderId: number; trackingNumber: string; carrier: string }; |
| 2 | type UnshippedOrder = { orderId: number; trackingNumber: null; carrier: null }; |
| 3 | type Order = ShippedOrder | UnshippedOrder; |
| 4 |
|
| 5 | // Only checks trackingNumber, but claims the whole ShippedOrder shape. |
| 6 | const isShipped = (order: Order): order is ShippedOrder => |
| 7 | order.trackingNumber !== null; |
| 8 |
|
| 9 | // carrier could still be null at runtime -> crash, even though TS is happy. |
| 10 | function label(order: Order) { |
| 11 | if (isShipped(order)) return order.carrier.toUpperCase(); |
| 12 | } |
Explanation (EN)
The predicate asserts the full ShippedOrder shape but only checks trackingNumber. TypeScript trusts the assertion, so reading carrier compiles fine yet can blow up at runtime if carrier is null while trackingNumber is set.
Objašnjenje (HR)
Predikat tvrdi cijeli ShippedOrder oblik, ali provjerava samo trackingNumber. TypeScript vjeruje toj tvrdnji, pa citanje carrier prolazi kompilaciju, ali se moze srusiti u izvodenju ako je carrier null dok je trackingNumber postavljen.
Good example
| 1 | const isShipped = (order: Order): order is ShippedOrder => |
| 2 | order.trackingNumber !== null && order.carrier !== null; |
| 3 |
|
| 4 | function label(order: Order) { |
| 5 | // Both fields are proven non-null, so the narrowing is sound. |
| 6 | if (isShipped(order)) return order.carrier.toUpperCase(); |
| 7 | } |
Explanation (EN)
Checking every field that the narrowed variant guarantees makes the type predicate sound, so the compiler's narrowing actually matches runtime reality and accessing any of those fields is safe.
Objašnjenje (HR)
Provjera svakog polja koje zajamcena varijanta osigurava cini tipski predikat ispravnim, pa suzivanje koje radi kompajler stvarno odgovara stvarnosti u izvodenju i pristup bilo kojem od tih polja je siguran.
Exceptions / Tradeoffs (EN)
If one field is a true discriminant tag (a literal union like `kind: 'shipped'`) that is guaranteed to co-vary with the others, checking that single tag is sufficient.
Iznimke / Tradeoffi (HR)
Ako je jedno polje pravi diskriminantni tag (literalna unija poput `kind: 'shipped'`) za koji je zajamceno da se mijenja zajedno s ostalima, dovoljno je provjeriti taj jedan tag.