Rules Hub
Code Ruleset
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Derive union types from constant objects
Use `keyof typeof` to generate union types from constant objects to ensure a single source of truth and prevent synchronization errors.
Bad example
| 1 | const STATUS_LABELS = { |
| 2 | draft: 'Draft', |
| 3 | published: 'Published', |
| 4 | archived: 'Archived', |
| 5 | }; |
| 6 |
|
| 7 | // BAD: The type is manually defined and disconnected from the object. |
| 8 | // If you add a key to STATUS_LABELS, you must remember to update this type. |
| 9 | type ArticleStatus = 'draft' | 'published' | 'archived'; |
| 10 |
|
| 11 | export const getLabel = (status: ArticleStatus) => STATUS_LABELS[status]; |
Explanation (EN)
A duplicated literal union can drift from its authoritative lookup keys.
Objašnjenje (HR)
Odvojeno prepisana literalna unija može se razići s mjerodavnim ključevima lookup objekta.
Good example
| 1 | const STATUS_LABELS = { |
| 2 | draft: 'Draft', |
| 3 | published: 'Published', |
| 4 | archived: 'Archived', |
| 5 | } as const; |
| 6 |
|
| 7 | // GOOD: The type is derived directly from the keys of the constant object. |
| 8 | // It automatically updates whenever the object changes. |
| 9 | type ArticleStatus = keyof typeof STATUS_LABELS; |
| 10 |
|
| 11 | export const getLabel = (status: ArticleStatus) => STATUS_LABELS[status]; |
Explanation (EN)
By using `as const` and `keyof typeof`, the configuration object becomes the Single Source of Truth. The type is automatically synchronized with the runtime values.
Objašnjenje (HR)
Korištenjem `as const` i `keyof typeof`, konfiguracijski objekt postaje jedini izvor istine (Single Source of Truth). Tip se automatski sinkronizira s runtime vrijednostima.
Notes (EN)
Derive a union from keys or values of the authoritative constant source when that source represents the complete intended domain.
Exceptions / Tradeoffs (EN)
keyof typeof yields keys, not values. A partial display map should not redefine a broader domain; use a domain union plus satisfies when completeness should be checked instead.