$npx -y skills add paleo/alignfirst --skill top-down-typescriptTypeScript and JavaScript coding style conventions, centered on top-down narrative ordering (caller first, helpers below) and functions over classes. Read before writing or reviewing TypeScript/JavaScript code, including code inside a spec or a plan.
| 1 | # Top-Down TypeScript Coding Style |
| 2 | |
| 3 | ## General Rules |
| 4 | |
| 5 | - Dead (unused) code SHOULD NOT be kept (_YAGNI principle_). |
| 6 | - Do not write multiple consecutive blank lines. |
| 7 | - Changes to linter rules MUST be discussed before being implemented. |
| 8 | - Code SHOULD NOT contain commented-out code, unless a comment explains why. |
| 9 | |
| 10 | ## Code Organization |
| 11 | |
| 12 | **Usage comes first**, implementation after. Exception: with inheritance — when an interface _extends_ another, write the parent first. |
| 13 | |
| 14 | - Order code top-down: each file reads as a story, from entry point to leaves. The reader meets the highest-level thing first, then drills down into its dependencies: |
| 15 | |
| 16 | ```ts |
| 17 | // 1. Imports |
| 18 | import { ... } from "..."; |
| 19 | |
| 20 | // 2. Module-level constants and variables (exported first, then internal) |
| 21 | export const PUBLIC_CONST = ...; |
| 22 | const INTERNAL_CONST = ...; |
| 23 | |
| 24 | // 3. Shared types — main type first, then types it references |
| 25 | export interface MainType { |
| 26 | detail: DetailType; |
| 27 | } |
| 28 | export interface DetailType { ... } |
| 29 | |
| 30 | // 4. Entry-point (exported) function |
| 31 | export function doThing() { |
| 32 | stepOne(); |
| 33 | stepTwo(); |
| 34 | } |
| 35 | |
| 36 | // 5. Internal functions called by the entry point, in call order |
| 37 | function stepOne() { |
| 38 | stepOneHelper(); |
| 39 | } |
| 40 | function stepOneHelper() { ... } |
| 41 | |
| 42 | function stepTwo() { ... } |
| 43 | ``` |
| 44 | |
| 45 | - Module-level constants and variables (`const`, `let`, `var` value declarations at the top of the file — both exported and internal) MUST be placed immediately after imports, before any type definitions, functions, or classes. The reader sees them first and treats them as the file's configuration surface. |
| 46 | - Functions: write the caller first, then the functions it calls, recursively. A helper appears _just below_ its caller, not grouped at the bottom of the file. If a helper is called by several siblings, place it after its first caller. |
| 47 | - Types: write the main (top-level) type first, then the types it references, recursively. Same top-down rule as functions. |
| 48 | - Types attached to a single function (or class, or other declaration) — i.e. used only in that one signature, like a `MyComponentProps` interface used only by `MyComponent` — must be placed immediately before that declaration, not in the top type block. |
| 49 | - Exports are not a sorting criterion on their own: a `function` being `export`ed does not pull it to the top — its position is determined by who calls it. The entry points of a file are usually exported, which is why they tend to appear first, but that is a consequence of the top-down rule, not the rule itself. |
| 50 | |
| 51 | ## Code Quality Standards |
| 52 | |
| 53 | - Strive for elegant solutions from the first implementation |
| 54 | - Avoid redundant operations, especially expensive ones like image conversion |
| 55 | - Avoid duplicated code and logic |
| 56 | - Pass previously calculated values between functions instead of recalculating |
| 57 | - Use early returns to simplify code flow when possible |
| 58 | - For code that leaves the current flow (`throw`, `return`, `continue`, `break`), when it fits on one line, write it on one line (e.g., `if (!condition) return false;` instead of multi-line format) |
| 59 | - Use function and variable names that clearly convey intent, reducing the need for comments |
| 60 | - Keep functions small with a single responsibility |
| 61 | - Avoid `any`; take the time to find the proper type. If you fail to find one, always insert a `/* FIXME */` after the `any`. For example: `let myVariable: any /* FIXME */;`. |
| 62 | - Export only functions (or variables, classes) that are imported from elsewhere. By default, do not export. |
| 63 | - When an interface is used in the signature of an exported function or component, that interface must also be exported. |
| 64 | |
| 65 | ## Imports |
| 66 | |
| 67 | - Always use ESM import syntax (e.g., `import { X } from "y.js"` instead of `require`). |
| 68 | - Avoid circular imports between modules. |
| 69 | |
| 70 | ## TypeScript, JavaScript |
| 71 | |
| 72 | - Never use `enum` and `namespace`. |
| 73 | - Prefer `const` over `let`. |
| 74 | - Prefer `undefined` over `null`. |
| 75 | - Prefer `??` over `||`. |
| 76 | - Prefer `++i` and `--i` over `i++` and `i--`. |
| 77 | - Prefer `new Error()` over `Error()`. |
| 78 | - At the top level, prefer the `function` and `class` declarative syntax over creating them as constants. |
| 79 | - Keep an empty line between top-level functions, classes, interfaces. |
| 80 | - Implementation of a getter or setter (EcmaScript 5 syntax) must never throw exceptions. |
| 81 | - Prefer `interface` declarations over `type` aliases. |
| 82 | - Prefer a single capital letter for generics parameters, such as `T`, `K`, etc. |
| 83 | - Do not differentiate between an absent property and a property with an `undefined` value. |
| 84 | - Use camelCase for string literal values in TypeScript union types (e.g., `"normal" | "gracefulShutdown" |