@groupby/ai-dev 0.5.14 → 0.5.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,491 @@
1
+ ---
2
+ name: typescript
3
+ description: Provides self-contained modern TypeScript authoring rules as a strict **extension** of the javascript skill (which embeds the full Airbnb JavaScript Style Guide as §A1–§A27 plus §B1–§B9 for topics Airbnb does not cover). This file embeds the **Google TypeScript Style Guide** as **§C1–§C15** (the most comprehensive standalone TS style guide today; parallel role to Airbnb for JS) and adds **§D1–§D3** for topics Google does not cover (`typescript-eslint` presets, React/JSX, Node/dual-module interop). The §A/§B JavaScript layer is **not duplicated here**—the TS skill only documents what is **TS-specific** plus a small override table where Google's TS guidance contradicts Airbnb's JS guidance. Agents must read the `javascript` skill first, then this file, before creating, editing, reviewing, or refactoring any `.ts`/`.tsx`/`.mts`/`.cts` file or TypeScript snippet (do not substitute memory). Auto-apply for `.ts`/`.tsx`, `tsconfig.json`, `typescript-eslint`, generics, narrowing, declaration files, or TS ecosystem questions.
4
+ ---
5
+
6
+ # TypeScript Best Practices Guide
7
+
8
+ ## Relationship to the JavaScript skill
9
+
10
+ TypeScript **is** JavaScript at runtime. Everything in the **javascript** skill applies to `.ts`/`.tsx`/`.mts`/`.cts` exactly as it applies to `.js`. This file is a **strict extension**, not a replacement: do **not** repeat **§A1–§A27** (Airbnb embedded) or **§B1–§B9** (additional rules) here. Apply them by reference.
11
+
12
+ The TS-specific embedded standard is **§C1–§C15** (the **Google TypeScript Style Guide**, the most comprehensive standalone TS style guide today) and **§D1–§D3** (topics Google does not cover).
13
+
14
+ ## Mandatory application (agents)
15
+
16
+ Whenever the task involves **TypeScript source**—including `.ts`, `.tsx`, `.mts`, `.cts`, or TypeScript-first snippets:
17
+
18
+ 1. **Read the `javascript` skill first.** At minimum: **Mandatory application**, **Purpose**, **Self-contained operating mode**, **§A1–§A27**, **§B1–§B9**, **Response workflow**.
19
+ 2. **Read this file second** for the TS layer.
20
+ 3. **Apply both.** When **§C** (Google TS) overrides **§A** (Airbnb JS) for TS-specific reasons, **§C wins on `.ts`/`.tsx` files**—see the **§C↔§A overrides** table below. Repository config (`tsconfig.json`, ESLint, Prettier/Biome, `.editorconfig`) wins on tie-breaks.
21
+
22
+ Do **not** skip the JavaScript skill because the file extension is `.ts`. For tasks that are strictly non-TypeScript (e.g. CSS-only edits with no TS files), this skill is optional until TypeScript is back in scope.
23
+
24
+ ## Inherited formatting (mandatory, no TS-side relaxation)
25
+
26
+ TS extends JS — it does **not** redefine layout. Every formatting rule in the **javascript** skill applies verbatim to `.ts`/`.tsx`/`.mts`/`.cts`. The agent satisfies them **by hand** when no formatter is configured; when Prettier/Biome **is** configured, that tool owns the bytes (see **§C13.3**). The current task wins over any stale user_rule (CLAUDE.md / AGENTS.md / etc.) that historically said otherwise.
27
+
28
+ The non-negotiable inherited sections:
29
+
30
+ | JS rule | What it says | TS-file consequence |
31
+ |---------|--------------|---------------------|
32
+ | **§A21 (semicolons)** | semicolons required, no ASI reliance | every statement, every type-alias declaration, every member of a `type`/`interface` body, every closing `};` of an arrow body assigned to a `const` |
33
+ | **§A20 (commas)** | trailing commas on every multiline literal/parameter list/argument list | applies to `type` and `interface` members too when each member is on its own line |
34
+ | **§A19.1–§A19.20 (whitespace)** | 2-space indent, single space around infix, no trailing spaces, exactly one trailing newline, max 100 cols | unchanged for TS |
35
+ | **§A19.7 (blank line after blocks)** | blank line after the closing `}` of any block construct (incl. arrow `{ … }` bodies, `try`/`catch`, `if`/`else`, etc.) before the next statement at the same indent | applies after every `const f = () => { … };` and after every catch block before subsequent code |
36
+ | **§A19.7b (paragraph blank lines)** | one blank line between adjacent paragraphs; **never** within a paragraph | see paragraph anatomy below |
37
+
38
+ ### Paragraph anatomy (§A19.7b applied to TS)
39
+
40
+ Treat every block body as a sequence of **paragraphs**. A paragraph is exactly **one** of:
41
+
42
+ 1. a **cluster of consecutive `const`/`let`/`var`** declarations (no blank lines internally — they belong to the same cluster);
43
+ 2. a **single block-like statement** (`if`/`else`, `for`/`for…of`/`for…in`, `while`/`do…while`, `try`/`catch`/`finally`, `switch`);
44
+ 3. a **`return`** or **`throw`** that ends the function/branch;
45
+ 4. a **sequence of effectful expression statements that act on the same target** — e.g. several `el.setAttribute(…)` calls in a row.
46
+
47
+ **Always-blank edges** (consequences):
48
+
49
+ - after any block-like statement before the next statement at the same indent (this is **§A19.7**);
50
+ - before any block-like statement when the previous statement is **not** another block;
51
+ - before any `return` / `throw` when it is **not** the only statement of its enclosing block;
52
+ - **after a declaration cluster before any non-declaration paragraph** — this is the rule agents miss most often. `const el = createX();` followed by `el.foo = …` means **blank line between them**, even when `el.foo = …` immediately consumes the freshly-created variable.
53
+
54
+ **Never-blank edges**: between two consecutive `const`/`let`/`var` declarations (same cluster); between statements inside a tight effectful sequence on the **same** target; at the very first or very last line inside `{ … }`.
55
+
56
+ Example — correct paragraph spacing in TS:
57
+
58
+ ```typescript
59
+ const createItemElement = (item: TodoItem): HTMLLIElement => {
60
+ const li = document.createElement('li');
61
+
62
+ li.className = 'todo-item';
63
+ li.dataset.done = String(item.done);
64
+
65
+ const checkbox = document.createElement('input');
66
+
67
+ checkbox.className = 'todo-item-check';
68
+ checkbox.type = 'checkbox';
69
+ checkbox.checked = item.done;
70
+
71
+ return li;
72
+ };
73
+ ```
74
+
75
+ `const li`, `const checkbox` are each declaration paragraphs; the `li.*` and `checkbox.*` lines are same-target effectful paragraphs. Blank lines separate every paragraph; **no** blank lines inside the same-target chains.
76
+
77
+ ## Purpose
78
+
79
+ Answer TypeScript implementation questions using the **embedded standard** below as the default. External URLs are **optional citations**, not prerequisites for routine typing or `tsconfig` decisions.
80
+
81
+ ## When to use
82
+
83
+ - Writing, editing, reviewing, or refactoring **TypeScript** (browser, Node, bundlers, `.tsx`/JSX)
84
+ - **`tsconfig.json`**, compiler flags, module resolution, JSX settings
85
+ - **`typescript-eslint`** presets, type-aware linting, optional **Prettier** or **Biome** when configured
86
+ - **Public API surfaces** (exports, props, RPC payloads), **generics**, **narrowing**, **declaration files**, JS→TS migration
87
+
88
+ ## When not to use
89
+
90
+ - **JavaScript-only** files (`.js`/`.mjs`/`.cjs`)—use the **javascript** skill alone.
91
+ - Primary topic is **CSS-only** or **HTML-only**—use sibling skills unless TS files are also edited.
92
+
93
+ ## Truthfulness and claims
94
+
95
+ Inherit **Truthfulness and claims** from the **javascript** skill. Additionally:
96
+
97
+ - Do **not** invent compiler flag defaults for **another** repository—read **this** repo's `tsconfig`.
98
+ - Do **not** rank a global "#1 TypeScript tutorial" without a defined metric and source.
99
+ - The **Google TypeScript Style Guide** is named here because it is the most comprehensive public TS-only style guide and is reproduced verbatim-by-rule below as **§C1–§C15**, **not** because the skill claims it is empirically "most used." `typescript-eslint` covers more lint rules but is a ruleset, not a prose style guide.
100
+
101
+ ## Authority precedence (highest first)
102
+
103
+ 1. **Explicit user instruction** in the current task.
104
+ 2. **Repository config:** `tsconfig.json`, ESLint, Prettier, Biome, `.editorconfig`. **Repo wins** over §C/§D and §A/§B for any rule it covers.
105
+ 3. **§C1–§C15** (this file, embedded Google TS defaults) for **TypeScript-specific** topics—and these **override §A** where the **§C↔§A overrides** table below calls it out.
106
+ 4. **§D1–§D3** (this file) for topics Google's TS guide does not cover.
107
+ 5. **§A1–§A27** (javascript skill, Airbnb embedded) for everything else.
108
+ 6. **§B1–§B9** (javascript skill, additional rules) likewise.
109
+ 7. **Optional citations** (URLs at the bottom)—only when user asks or verification is explicitly needed.
110
+
111
+ When repo or user disagrees, follow them and note the deviation succinctly.
112
+
113
+ ---
114
+
115
+ ## §C↔§A overrides (TS-specific exceptions to Airbnb JS rules)
116
+
117
+ These are the only places where this skill **intentionally diverges** from the javascript skill's embedded Airbnb defaults. On `.ts`/`.tsx` files, **§C wins**.
118
+
119
+ | Topic | Airbnb (§A, javascript skill) | Google TS (§C, this file) | TS rule wins because |
120
+ |-------|-------------------------------|---------------------------|----------------------|
121
+ | Default exports | **§A10.6:** single-export modules **should use a default export** | **§C1.3:** **never** use `default` exports; named exports only | Default exports lose canonical names, defeat rename refactors, and silently mismatch with `import type` |
122
+ | Acronym casing | **§A23.9:** acronyms are **all-uppercase or all-lowercase consistently** (`HTTPRequests`, `httpRequests`) | **§C10.4:** acronyms are treated as **whole words** (`loadHttpUrl`, `customerId`, `XMLHttpRequest` only when the platform name forces it) | Avoids the run-on `URLHTTPID` problem in TS-heavy codebases and matches `@types/*` |
123
+ | Class accessors | **§A24.2:** do **not** use `get`/`set` syntax | **§C5.7:** `get`/`set` allowed when the getter is **pure** (no observable state change) and the accessor hides non-trivial implementation | TS class visibility + `readonly` makes safe accessors expressible; tooling integrates with them |
124
+ | Number parsing | **§A22.3:** `parseInt(x, 10)` for parsing | **§C7.4:** `Number(x)` (+ `isFinite` check + `Math.floor`/`Math.trunc`) for base-10; `parseInt` only for non-base-10 with prior format validation | `parseInt('12dwarves', 10)` returns `12`—silently masks bad input |
125
+ | Function declaration vs expression | **§A7.1:** prefer **named function expression** assigned to `const` | **§C6.1:** prefer **`function` declarations** for top-level named functions; arrow functions for callbacks and when an explicit type is required | Function declarations get cleaner stack frames and hoist predictably for top-level helpers; arrow functions remain canonical for callbacks (matches §A8.1) |
126
+
127
+ All other §A and §B rules apply to TS unchanged. (Formatting inheritance is documented in **Inherited formatting** above, not duplicated here.)
128
+
129
+ ---
130
+
131
+ ## Project deviations from §C (Google TS)
132
+
133
+ These are places where this project's defaults intentionally differ from Google's TS Style Guide. Apply this column on every new TS file.
134
+
135
+ | Topic | Google TS (§C) | This project | Rationale |
136
+ |-------|----------------|--------------|-----------|
137
+ | Object type shapes | **§C4.1:** `interface User { … }` | **`interface User { … }`** — same as Google's default | `docs/architecture/12-code-conventions/06-typescript.md` is explicit: use `interface` for object shapes, `type` for unions and aliases. Reserve `type` for union types (`type Status = 'idle' \| 'loading'`), mapped types, conditional types, and type aliases where `interface` cannot express the shape. |
138
+ | Import paths | **§C1.8:** relative paths within the project | **`@/` alias** for all cross-module imports | `@/` resolves to `src/`. Use `@/utils/logger`, `@/platform-services/rules`, etc. Relative paths (`../../../`) are banned across module boundaries; relative imports within the same module (`./RuleTableRow`) are fine. Import order: React → third-party → `@/` → `./`. |
139
+ | TypeScript strict mode | **§C2.1:** `"strict": true` default | `"strict": false` (legacy concession) | The project runs `strict: false` in `tsconfig.json` due to the existing codebase. Do not suppress TS errors with `// @ts-ignore` without an explanatory comment, and do not introduce new patterns that would fail under strict mode. Tighten flag-by-flag as modules are migrated. |
140
+ | Model files | n/a | Entity types in `<entity>.model.ts` | TypeScript interfaces and types for an entity live in `<entity>.model.ts` (e.g. `rule.model.ts`). Shared cross-entity types live in `src/search-for-retail/models/`. |
141
+
142
+ ---
143
+
144
+ ## Embedded implementation standard
145
+
146
+ The §C sections below mirror the public **Google TypeScript Style Guide** ([google.github.io/styleguide/tsguide.html](https://google.github.io/styleguide/tsguide.html)) section by section, in this skill's own numbering, so agents can apply every rule without opening the URL.
147
+
148
+ > **Convention in code examples below:** `// good` blocks are normative; `// bad` blocks are anti-patterns. Apply the `// good` form unless authority precedence overrides it.
149
+
150
+ ---
151
+
152
+ ### §C1) Source file structure, imports, and exports
153
+
154
+ - **§C1.1 File order.** Files contain, in order: (1) copyright (if any) in JSDoc; (2) `@fileoverview` JSDoc (if any); (3) imports; (4) implementation. Exactly one blank line separates each section.
155
+ - **§C1.2 Import variants.** Four shapes—use as appropriate:
156
+ - **Named** (`import { Foo } from '...'`)—preferred for symbols used frequently or with clear names.
157
+ - **Namespace** (`import * as ns from '...'`)—preferred when consuming many symbols from a large module.
158
+ - **Default** (`import Foo from '...'`)—**only** when an external module truly requires it.
159
+ - **Side-effect** (`import 'jasmine'`)—only for libraries imported for load-time side effects.
160
+ - **§C1.3 No default exports.** Always use **named exports** (overrides **§A10.6**). Default exports give every importer a different identifier, break rename refactors, and silently allow `import {fizz} from './foo'` to fail differently from `import fizz from './foo'`.
161
+
162
+ ```typescript
163
+ // good
164
+ export class Foo { /* … */ }
165
+
166
+ // bad
167
+ export default class Foo { /* … */ }
168
+ ```
169
+ - **§C1.4 No namespaces / no internal modules.** `namespace Foo {}`, `module Foo {}`, and `import x = require('...')` are forbidden in first-party code. Use ES modules and one file per logical namespace. `namespace` is allowed **only** to interface with third-party ambient typings.
170
+ - **§C1.5 No mutable exports.** `export let` is banned (matches **§A10.5**). Use a getter function if a runtime-mutable value must be exposed.
171
+ - **§C1.6 No container classes for namespacing.** Do **not** group constants/functions as `static` members of a "Container" class purely for namespacing—use the file as the namespace and export individual symbols.
172
+ - **§C1.7 `import type` / `export type`.** Use `import type { Foo } from '...'` when the symbol is referenced **only** as a type; use regular `import` for values. `import { type Foo, Bar } from '...'` is allowed for mixed cases. Mirror with `export type { … } from '...'` for type-only re-exports. Pair with **`verbatimModuleSyntax`** (see **§C2.1**).
173
+ - **§C1.8 Import paths.** Use **relative** paths (`./sibling`, `../parent`) within the same logical project; use rooted paths across projects. Limit `../../../` depth.
174
+ - **§C1.9 Renaming.** `import { Foo as Bar }` is allowed to resolve collisions, clarify generated names, or rename ambiguous exports (e.g. RxJS `from` → `observableFrom`).
175
+ - **§C1.10 Minimize export surface.** TS does not enforce package-private visibility—only `export` symbols actually consumed outside the module.
176
+
177
+ ---
178
+
179
+ ### §C2) Compiler baseline (`tsconfig.json`)
180
+
181
+ - **§C2.1 `"strict": true`** is the default for new work (bundles `noImplicitAny`, `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `noImplicitThis`, `useUnknownInCatchVariables`, `alwaysStrict`). Legacy codebases tighten incrementally—prefer flag-by-flag adoption over silent `any` spread.
182
+ - **§C2.2 `noUncheckedIndexedAccess`** strongly preferred so `arr[i]` is `T | undefined`.
183
+ - **§C2.3 `exactOptionalPropertyTypes`** when feasible: optional props are not the same as `| undefined`—model APIs explicitly.
184
+ - **§C2.4 `verbatimModuleSyntax`** so type-only imports/exports stay explicit at runtime (pairs with **§C1.7**).
185
+ - **§C2.5 Module/resolution.** Node packages: `"module": "nodenext"` + `"moduleResolution": "nodenext"`, aligned with `package.json` `"type"` and `.mts`/`.cts`. Bundled apps: follow the bundler/tsconfig preset (`"module": "esnext"` / `"moduleResolution": "bundler"`).
186
+ - **§C2.6 `jsx`.** React: `"react-jsx"` (or `"react-jsxdev"`) for the modern automatic runtime, or `"preserve"` if a downstream tool transforms JSX. `"jsxImportSource"` only for non-default JSX runtimes.
187
+ - **§C2.7 `target`/`lib`.** Match supported runtimes; include `"DOM"` only for browser code. Do not invent flag defaults for another repo—read **this** project's `tsconfig`.
188
+
189
+ ---
190
+
191
+ ### §C3) Type system: inference, annotations, and assertions
192
+
193
+ - **§C3.1 Trust inference for trivial types.** Omit annotations for variables initialized to a string/number/boolean/regex literal or a `new` expression: `const x = 15;`, not `const x: number = 15;`.
194
+ - **§C3.2 Annotate when it aids reading.** Add annotations when the right-hand side is opaque (an `await`ed call, a generic with no concrete arg). Annotate function **parameters and exported return types** at module boundaries.
195
+ - **§C3.3 Generic anchors.** Initializing empty generic containers (`new Set<string>()`, `new Map<string, User>()`) **requires** an explicit type parameter—otherwise the type is inferred as `unknown`.
196
+ - **§C3.4 `unknown` over `any`.** Use `unknown` for truly opaque inputs (parsed JSON, untrusted callbacks). Narrow with `typeof`, `Array.isArray`, `instanceof`, discriminants, or schema validators before use. `any` is a last resort: **scope narrowly + comment why**.
197
+ - **§C3.5 No `@ts-ignore`, `@ts-nocheck`.** They mask root causes. `@ts-expect-error` is allowed in **tests only**, with a comment explaining the suppression.
198
+ - **§C3.6 Assertion syntax: `as`.** Use `value as Foo`, never `<Foo>value`. The `as` form survives JSX parsing.
199
+ - **§C3.7 Double assertion via `unknown`.** When a direct `as` is rejected, route through `unknown`: `(value as unknown as Foo)`. Never via `any` or `{}`.
200
+ - **§C3.8 Annotate object literals; do not assert them.** `const foo: Foo = { … }` catches refactoring drift; `const foo = { … } as Foo` does not. Same for return positions: declare the return type instead of asserting at the `return`.
201
+ - **§C3.9 Avoid `!` (non-null assertion).** Prefer narrowing (`if (y) y.bar()`) or `instanceof`. When `!` is unavoidable, comment why the value is provably defined.
202
+
203
+ ---
204
+
205
+ ### §C4) Type modeling
206
+
207
+ - **§C4.1 (project aligns with Google default) Interfaces for object shapes; types for unions and aliases.** Use `interface User { … }` for object shapes — this aligns with Google's published recommendation and with `docs/architecture/12-code-conventions/06-typescript.md`. Use `type` for union types, mapped types, conditional types, and aliases where `interface` cannot express the shape (e.g. `type Status = 'idle' | 'loading'`). Reserve `interface` declaration merging only for ambient module augmentation or extending third-party `interface`s. See **Project deviations from §C** table above.
208
+ - **§C4.2 Discriminated unions** for finite state. Share a literal field (`kind`, `type`, `status`) and `switch` on it; assign the `default` branch to a `never`-typed variable for exhaustiveness.
209
+ - **§C4.3 No nullable type aliases.** Do **not** bake `| null` / `| undefined` into a `type` alias; add nullability **at the use site** so callers see absence locally.
210
+
211
+ ```typescript
212
+ // good
213
+ type CoffeeResponse = Latte | Americano
214
+
215
+ class CoffeeService {
216
+ getLatte(): CoffeeResponse | undefined { /* … */ }
217
+ }
218
+
219
+ // bad
220
+ type CoffeeResponse = Latte | Americano | undefined
221
+ ```
222
+ - **§C4.4 Optional `?` over `| undefined`.** Prefer `interface CoffeeOrder { milk?: Milk }` and `function pour(volume?: Liter)` over explicit `| undefined`.
223
+ - **§C4.5 Array sugar.** `T[]` and `readonly T[]` for simple element types; `Array<T>` / `ReadonlyArray<T>` only when `T` is a complex expression (union, object literal, etc.). Apply at every nesting level.
224
+ - **§C4.6 Tuples over `Pair`-style interfaces.** `function splitInHalf(s: string): [string, string]`. When names help, prefer an inline object: `function splitHostPort(s: string): { host: string, port: number }`.
225
+ - **§C4.7 Index signatures.** `{ [fileName: string]: number }` is allowed; the key label is documentation only. Prefer `Map`/`Set` for general dictionaries (non-string keys, no prototype surprises) and `Record<K, V>` for known key sets.
226
+ - **§C4.8 Mapped & conditional types: only when they remove real duplication.** Prefer plain interfaces and extension. The cost is reader load, fragile inference across compiler versions, and broken `Find references` / rename in IDEs.
227
+ - **§C4.9 No `{}` for general "any object."** Prefer `unknown` (any value), `Record<K, V>` (dictionary), or `object` (non-primitive non-null).
228
+ - **§C4.10 No wrapper types `String`/`Boolean`/`Number`** in annotations—use `string`/`boolean`/`number`. Never `new String(x)` either (covered by **§A22.2**, **§A22.3**, **§A22.6**).
229
+ - **§C4.11 No return-type-only generics.** Avoid `function decode<T>(input: string): T`—the caller has no inference anchor and is forced to assert. If you encounter such an API, always pass the type parameter explicitly at the call site.
230
+ - **§C4.12 Use structural types at the declaration site.** Annotate the variable, not the consumer: `const horse: Animal = { … }` puts the error at the bad object; `makeSound({ sound: 'meow' })` puts the error far from the bug.
231
+
232
+ ---
233
+
234
+ ### §C5) Classes
235
+
236
+ - **§C5.1 Visibility.** Use TS `private`/`protected`. **No `#private` fields**—they bloat downlevel emit, do not work below ES2015, and add no real safety on top of the type checker. Never use `obj['foo']` to bypass `private`.
237
+ - **§C5.2 No `public` modifier** (TS default is public). Allowed only on **non-`readonly` parameter properties** in a constructor, where it carries actual meaning.
238
+ - **§C5.3 `readonly`** for any property never reassigned outside the constructor (need not be deeply immutable).
239
+ - **§C5.4 Parameter properties** for trivial assignments: `constructor(private readonly bar: BarService) {}` instead of declaring + reassigning.
240
+ - **§C5.5 Field initializers at declaration** when possible—lets you delete the constructor entirely. Do **not** add or remove properties after the constructor finishes; initialize optional fields explicitly to `undefined` to keep the object's hidden class stable.
241
+ - **§C5.6 `new Foo()` always with parens.** `new Foo` and `new Foo.Bar()` parse differently and silently change behavior.
242
+ - **§C5.7 Getters/setters allowed (overrides §A24.2)** when the getter is **pure** (no observable state change) and the accessor hides non-trivial implementation. Do **not** define getters/setters via `Object.defineProperty`. At least one accessor must be non-trivial—do not write pass-through accessors just to hide a property; mark it `readonly` instead.
243
+ - **§C5.8 No `private static` methods**—prefer module-local non-exported functions. Static methods should be called only on the base class that defines them; do not rely on dynamic dispatch through subclass constructors.
244
+ - **§C5.9 No `this` in static context.** Static fields are inherited along the prototype chain via `this`, which surprises readers and resists testing.
245
+ - **§C5.10 No empty / pure-delegating constructors.** Omit `constructor() {}` and `constructor(value: number) { super(value); }`. Keep constructors with parameter properties, visibility modifiers, or decorators—even if empty.
246
+ - **§C5.11 No prototype manipulation, no mixins** in first-party code. Framework code (Polymer, Angular) is exempted where it must hook into prototypes.
247
+ - **§C5.12 `toString()`** may be overridden but must succeed and be side-effect-free—beware infinite loops via methods that themselves call `toString`.
248
+
249
+ ---
250
+
251
+ ### §C6) Functions
252
+
253
+ - **§C6.1 Function declarations for top-level named functions** (overrides **§A7.1** for TS): `function foo() { … }`. Use **arrow functions** for callbacks (matches **§A8.1**) and when an explicit function type annotation is required: `const fooSearch: SearchFunction = (s, sub) => …`.
254
+ - **§C6.2 No `function` expressions** (`bar(function () {…})`). Use arrow functions—exception only for generators (`function*`) or genuine `this` rebinding.
255
+ - **§C6.3 Concise vs block arrow bodies.** Concise body **only** when the return value is used. When the return is discarded, use a block body so the inferred return is `void`—prevents accidental promise leaks (`myPromise.then(v => console.log(v))` returns the `console.log` result; use `myPromise.then(v => { console.log(v) })` or `myPromise.then(v => void console.log(v))`).
256
+ - **§C6.4 Forward callback args explicitly.** `['11', '5', '10'].map(parseInt)` returns `[11, NaN, 2]` because `map` passes the index as the second arg. Wrap: `.map(n => parseInt(n, 10))` (or use `Number`, see **§C7.4**).
257
+ - **§C6.5 Arrow function class properties only for handler stability.** Arrow methods on a class auto-bind `this` but obscure call-site semantics and complicate `super` chains. Use them when (a) the same handler must be `addEventListener`'d and `removeEventListener`'d, or (b) a template needs a stable bound reference. Otherwise wrap call-time: `setTimeout(() => this.tick(), 5000)`.
258
+ - **§C6.6 `this` discipline.** Use `this` only inside class constructors/methods, functions with an explicit `this:` parameter (`function fn(this: Ctx, …)`), or arrow functions in scopes where `this` is meaningful. Never as a stand-in for the global object.
259
+ - **§C6.7 Default parameters: simple and side-effect-free.** No `function newId(index = globalCounter++) {}`. Prefer destructuring with defaults when there are several optional parameters with no natural order.
260
+ - **§C6.8 Rest/spread.** Use `...args` for variadics and spread for forwarding (`fn(...arr)`)—never `arguments`, never `Function.prototype.apply` (matches **§A7.6**, **§A7.14**).
261
+
262
+ ---
263
+
264
+ ### §C7) Primitives, coercion, and parsing
265
+
266
+ - **§C7.1 Single quotes; template literals for interpolation.** Matches **§A6.1**, **§A6.3**.
267
+ - **§C7.2 No line continuations** (`'foo \` + newline). Concatenate explicit string segments instead, or keep a single long literal that stays grep-able.
268
+ - **§C7.3 Coercion.** `String(x)`, `Boolean(x)` / `!!x`, template literals—**no `new String(x)`**, no `+ ''`, no unary `+`. Matches **§A22**.
269
+ - **§C7.4 Number parsing (overrides §A22.3 for base-10).** Use `Number(x)` for base-10, then check `isFinite` and apply `Math.floor`/`Math.trunc` if integer is required:
270
+
271
+ ```typescript
272
+ const n = Number(input)
273
+
274
+ if (!isFinite(n)) {
275
+ handleError()
276
+ }
277
+
278
+ const integer = Math.floor(n)
279
+ ```
280
+
281
+ `parseInt(input, radix)` is allowed **only** for non-base-10 strings, and **only after** validating the input matches the radix's allowed digits with a regex. Never rely on `parseInt` for decimal—`parseInt('12dwarves', 10)` returns `12` and silently masks bad input.
282
+ - **§C7.5 Enums never coerce to boolean.** First-declared enum members are `0` (falsy) by default; readers cannot tell. Compare explicitly: `level !== Level.NONE`, not `Boolean(level)` or `if (level)`.
283
+ - **§C7.6 Implicit boolean coercion in conditions.** `if (foo)`, `while (foo)` are fine for nullable references and strings—do **not** add `!!`. The enum exception above still applies.
284
+
285
+ ---
286
+
287
+ ### §C8) Control flow
288
+
289
+ - **§C8.1 Braces always.** All `if`/`else`/`for`/`while`/`do` blocks use braces, even single-statement bodies. **Exception:** a one-line `if (x) x.doFoo()` may elide braces (matches **§A16.1**).
290
+ - **§C8.2 No assignment in control conditions** (`if (x = fn())`). If intentional, double-parenthesize: `while ((x = fn())) { … }`.
291
+ - **§C8.3 Iterating containers.** `for (const x of arr)` for arrays. `Array.prototype.forEach` and indexed `for` loops are also allowed when the index is needed. Never `for (… in arr)`—it gives string indices, not values.
292
+ - **§C8.4 Iterating objects.** Prefer `for (const k of Object.keys(o))`, `Object.values(o)`, `Object.entries(o)`. If `for-in` is used, gate with `if (!o.hasOwnProperty(k)) continue` (or use `Object.hasOwn(o, k)` on ES2022+).
293
+ - **§C8.5 `switch`.** Every `switch` has a `default` clause **last** (even if empty). Non-empty cases must terminate (`break`, `return`, `throw`); the compiler enforces no fall-through. Empty cases may fall through.
294
+ - **§C8.6 Equality.** `===` / `!==` always (matches **§A15.1**). **Single exception:** `== null` / `!= null` may be used as a shorthand for `=== null || === undefined`.
295
+ - **§C8.7 Grouping parens.** Add parentheses whenever operator precedence is not common-knowledge obvious. Do **not** add unnecessary parens after `delete`, `typeof`, `void`, `return`, `throw`, `case`, `in`, `of`, `yield`.
296
+
297
+ ---
298
+
299
+ ### §C9) Errors and exception handling
300
+
301
+ - **§C9.1 `throw new Error(…)`.** Always with `new` (consistent with other constructor calls).
302
+ - **§C9.2 Throw only `Error` subtypes.** Throwing strings/objects loses stack traces; `Promise.reject('oops')` is equivalent to `throw 'oops'` in `async` functions and is just as bad. Subclass `Error` for domain errors.
303
+ - **§C9.3 `catch (e: unknown)`** (the strict-mode default). Narrow before use:
304
+
305
+ ```typescript
306
+ function assertIsError(e: unknown): asserts e is Error {
307
+ if (!(e instanceof Error)) {
308
+ throw new Error('e is not an Error')
309
+ }
310
+ }
311
+
312
+ try {
313
+ doThing()
314
+ } catch (e: unknown) {
315
+ assertIsError(e)
316
+ displayError(e.message)
317
+ }
318
+ ```
319
+
320
+ Do **not** defensively handle non-`Error` types unless the called API is known to throw non-`Error`s—comment that fact at the catch.
321
+ - **§C9.4 No empty catch blocks** without an explanatory comment.
322
+ - **§C9.5 Keep try blocks focused.** Move calls that don't throw out of the `try`; widen only when needed (e.g. a hot loop where extracting hurts performance).
323
+ - **§C9.6 Cause chaining.** When rewrapping, pass the original via `cause`: `throw new Error('failed to load X', { cause: err })`. Matches **§B3**.
324
+
325
+ ---
326
+
327
+ ### §C10) Naming
328
+
329
+ - **§C10.1 Categories** (table-form):
330
+
331
+ | Style | Used for |
332
+ |-------|----------|
333
+ | `UpperCamelCase` | classes, interfaces, types, enums, decorators, type parameters, TSX component functions |
334
+ | `lowerCamelCase` | variables, parameters, functions, methods, properties, module aliases |
335
+ | `CONSTANT_CASE` | module-level immutable constants and enum values **only** |
336
+ | `#ident` | **never** (see **§C5.1**) |
337
+
338
+ - **§C10.2 ASCII identifiers.** Letters, digits, underscores (only in test names and `CONSTANT_CASE`), `$` only when a third-party framework requires it.
339
+ - **§C10.3 No `_` prefix or suffix** (no `_foo`, `foo_`, `__foo__`); no bare `_` as identifier (use comma elision in destructuring: `const [a, , b] = arr`).
340
+ - **§C10.4 Acronyms as whole words (overrides §A23.9).** `loadHttpUrl`, `customerId`, `referrerUrl`. The only exception is when the platform itself spells the name with mixed case, e.g. `XMLHttpRequest`. **Never** `loadHTTPURL` or `customerID`.
341
+ - **§C10.5 Type parameters.** Single uppercase letter (`T`, `K`, `V`) or `UpperCamelCase` (`TElement`, `TError`).
342
+ - **§C10.6 Module aliases vs filenames.** Module namespace aliases are `lowerCamelCase` even when files are `snake_case`: `import * as fooBar from './foo_bar'`.
343
+ - **§C10.7 Constants.** `CONSTANT_CASE` only for **module-level** values that are conceptually immutable. Local `const`s inside a function stay `lowerCamelCase`. An arrow function bound to an interface may stay `lowerCamelCase`.
344
+ - **§C10.8 Aliases match source casing.** `const { BrewStateEnum } = SomeType`—do not rename to a different casing.
345
+ - **§C10.9 Descriptive over abbreviated.** `errorCount`, not `nErr`. Short names (`i`, `a`) are allowed only for variables in scope ≤10 lines (or non-exported function parameters).
346
+ - **§C10.10 No type-decoration in names.** Don't include type info that the type already carries (`opt_foo`, Hungarian notation).
347
+
348
+ ---
349
+
350
+ ### §C11) Decorators
351
+
352
+ - **§C11.1 Do not define new decorators.** Use only those provided by frameworks (Angular `@Component`/`@NgModule`/`@Input`, Polymer `@property`, etc.). The TC39 decorator proposal has diverged from the experimental implementation; avoid lock-in.
353
+ - **§C11.2 Decorator placement.** Decorators sit immediately before the symbol they decorate, with no blank line between them. JSDoc comes **before** the decorator, not between decorator and target.
354
+
355
+ ---
356
+
357
+ ### §C12) Disallowed features
358
+
359
+ - **§C12.1 No `const enum`.** Use plain `enum`. `const enum` makes the enum invisible to JS importers and relies on whole-program inlining that bundlers handle inconsistently.
360
+ - **§C12.2 No `with`, `eval`, `Function(...string)`** (matches **§A6.4**, **§B7**). `debugger` statements never ship to production.
361
+ - **§C12.3 No wrapper-type constructors.** Never `new String(x)`, `new Boolean(x)`, `new Number(x)` (`new Boolean(false)` is **truthy**). Calling them as functions for coercion is fine—see **§C7.3**.
362
+ - **§C12.4 No modifying built-in prototypes** and no adding global symbols unless a third-party API forces it.
363
+ - **§C12.5 No non-standard / proposal-stage features.** Stick to the current ECMA-262. Runtime-targeted projects (Node, Chrome extensions, Electron) may use runtime APIs but should isolate them.
364
+
365
+ ---
366
+
367
+ ### §C13) Lint and format (`typescript-eslint`)
368
+
369
+ - **§C13.1 Preset stack.** Combine `@eslint/js`'s `recommended` config with one or more `typescript-eslint` presets:
370
+ - `recommended` — non-typed quick wins.
371
+ - `recommended-type-checked` — adds rules requiring type info (`projectService` or `project` in the parser config).
372
+ - `strict` / `strict-type-checked` — opinionated, catch-more.
373
+ - `stylistic` / `stylistic-type-checked` — consistency-only rules.
374
+
375
+ Follow **this** repo's ESLint config; do not invent presets.
376
+ - **§C13.2 Type-aware rules cost CPU** but catch real bugs (`no-floating-promises`, `await-thenable`, `no-misused-promises`). Enable them in CI when the lint job fits in the time budget.
377
+ - **§C13.3 Mechanical layout.**
378
+ - **No formatter configured:** **§A19** (whitespace), **§A20** (commas), **§A21** (semicolons), and the rest of §A govern print layout (agent-authored).
379
+ - **Prettier or Biome configured:** the formatter owns layout. **Do not fight the formatter** in review—change the config if the team agrees. Pair with `eslint-config-prettier` (or Biome's ESLint integration) so layout rules are not double-enforced.
380
+ - **§C13.4 Biome** can replace both ESLint and Prettier in some setups. Follow this repo's single source of truth for `lint`/`check`/`format` scripts.
381
+
382
+ ---
383
+
384
+ ### §C14) Comments and JSDoc (TS-specific layer over §A18)
385
+
386
+ - **§C14.1 JSDoc vs implementation comments.** `/** … */` is for **API documentation** (read by editors and doc generators); `// …` is for implementation comments. Multi-line implementation comments **stack `//` lines**, not `/* */` blocks.
387
+ - **§C14.2 No type info in JSDoc.** TypeScript already encodes types—do **not** write `@type`, `@param {string}`, `@return {Foo}`, `@implements`, `@enum`, `@private`, `@override`. Use the language keywords. `@param name description` (without a type) is fine when description adds value.
388
+ - **§C14.3 `@param`/`@return` only when they add information.** Skip if the name and type are self-explanatory.
389
+ - **§C14.4 Document parameter properties** with `@param` JSDoc on the constructor; editors surface them at call sites and on field access.
390
+ - **§C14.5 JSDoc before decorators**, not between decorator and class/method (matches **§C11.2**).
391
+ - **§C14.6 Markdown in JSDoc.** Use Markdown lists and code fences—plain hard breaks render as run-on text.
392
+ - **§C14.7 `@deprecated`** on deprecated symbols, with concrete migration directions.
393
+
394
+ ---
395
+
396
+ ### §C15) Consistency, conformance, and reformatting
397
+
398
+ - **§C15.1 In-file consistency wins ties.** When a question is not settled by §A/§B/§C/§D or repo config, do what the file already does; then the directory; then default to Google TS / Airbnb JS.
399
+ - **§C15.2 New files use this skill's stack** (Airbnb §A + this file's §C/§D) regardless of surrounding files. When adding meaningful new code to a non-conforming file, reformat the file first—as a separate commit if scope creep is a concern.
400
+ - **§C15.3 Conformance frameworks.** Tools like `tsetse` and `tsec` enforce critical/security restrictions; treat their findings as build failures, not lint suggestions.
401
+
402
+ ---
403
+
404
+ ## §D) Additional rules beyond Google's TS guide
405
+
406
+ These TS topics are not covered by Google's guide; this skill adds them as authoritative defaults.
407
+
408
+ ### §D1) React and JSX (`.tsx`)
409
+
410
+ - **§D1.1** JSX lives in `.tsx`. Configure `tsconfig` `jsx` per **§C2.6**.
411
+ - **§D1.2 Component props.** Define with `interface Props { … }` (aligns with **§C4.1 project convention**); inline for trivially small one-off components, extract to `<entity>.model.ts` when shared or when shape grows past ~3 fields.
412
+ - **§D1.3 Hooks.** `useState` / `useReducer` infer from the initial value; add an explicit type parameter when the state is a union (`useState<User | null>(null)`) or starts as `[]`/`{}` and grows.
413
+ - **§D1.4 Events.** Use the React event types (`React.ChangeEvent<HTMLInputElement>`, `React.MouseEvent<HTMLButtonElement>`, `React.FormEvent<HTMLFormElement>`) when the inferred type from JSX is not flowing through.
414
+ - **§D1.5 `children`.** `React.ReactNode` for the broad case (allows strings, numbers, arrays, fragments). Use `React.ReactElement` only when restricting to elements.
415
+ - **§D1.6 `useContext` with nullable defaults.** When the default value is `null`, wrap access in a custom hook that `throw`s if the provider is missing—callers then get a non-null `T`, not `T | null`.
416
+ - **§D1.7 Component-function naming.** `UpperCamelCase` (per **§C10.1**); the file containing the default export of a component conventionally matches the component name.
417
+
418
+ ### §D2) Node, runtimes, and dual modules
419
+
420
+ - **§D2.1 `@types/node`** as a `devDependency` whenever Node globals or APIs are referenced.
421
+ - **§D2.2 `.mts` / `.cts`** match the ESM/CJS intent and override `package.json` `"type"` per file. Prefer `.ts` + a single repo-wide `"type"` setting unless interop forces dual emit.
422
+ - **§D2.3 Type-stripping runtimes** (Node native TS, ts-node `--transpile-only`, Bun) **do not replace** `tsc --noEmit` and type-aware `typescript-eslint` in CI unless the project explicitly standardizes on transpile-only.
423
+ - **§D2.4 Path resolution.** Prefer the `node:` prefix for built-ins (`import { readFile } from 'node:fs/promises'`) so the resolver can never confuse them with userland packages.
424
+
425
+ ### §D3) Boundaries, validation, and security
426
+
427
+ - **§D3.1 Validate at the boundary.** `JSON.parse` returns `unknown` (with `noImplicitAny` and `useUnknownInCatchVariables`); pass through a schema validator (Zod, Valibot, ArkType) before treating as a typed object. Do not assert.
428
+ - **§D3.2 Treat env vars as untyped strings.** `process.env.X` is `string | undefined`—parse, validate, and re-export typed config.
429
+ - **§D3.3 No types in serialized payloads.** Branded types (`type UserId = string & { __brand: 'UserId' }`) provide compile-time safety only; never assume the runtime payload still carries the brand. Re-validate.
430
+ - **§D3.4 Error-shape contracts.** For libraries, document the exact error subclasses thrown (or returned) in the public types. Consumers should be able to `instanceof`-narrow without reading source.
431
+
432
+ ---
433
+
434
+ ## Authority reasoning (embedded)
435
+
436
+ - **TypeScript compiler semantics** are normative for type behavior; for edge cases prefer **minimal repro + `tsc --noEmit`** over guessing.
437
+ - **Framework typings** (`@types/react`, `@types/node`, `@types/express`) model intent—pin versions and narrow at boundaries when they drift.
438
+ - **Surveys** (State of JS, Stack Overflow) measure adoption, not correctness.
439
+ - **Lint/format configs** are team law when present; absent formatters do not relax §A, §B, or §C.
440
+
441
+ ---
442
+
443
+ ## Response workflow (for the agent)
444
+
445
+ 1. If TypeScript is in scope: **read the `javascript` skill first**, then **read this file**.
446
+ 2. Apply **§A1–§A27** (Airbnb embedded in javascript skill) and **§B1–§B9** to all `.ts`/`.tsx` output, **except** where the **§C↔§A overrides** table above gives §C precedence.
447
+ 3. Apply **§C1–§C15** (Google TS embedded) for type system, `tsconfig`, classes, errors, naming, decorators, and disallowed features.
448
+ 4. Apply **§D1–§D3** for React/JSX, Node interop, and boundary validation.
449
+ 5. **Tie-break** using **explicit user instruction → repo config (`tsconfig`, ESLint, formatter, `.editorconfig`) → §C → §D → §A → §B**.
450
+ 6. Offer **optional citations** only when the user asks or when verification is explicitly needed.
451
+ 7. If a deliverable conflicts with a rule for a defensible reason (e.g. a third-party SDK requires a default export), call out the deviation explicitly.
452
+
453
+ ---
454
+
455
+ ## Quality bar before final answer
456
+
457
+ - Guidance cites **embedded sections** (§A/§B/§C/§D), not unnamed blogs.
458
+ - **JavaScript** Airbnb defaults preserved on `.ts`/`.tsx` **except** at the §C↔§A override points listed above.
459
+ - **`tsconfig` / ESLint / formatter** tie-breaks respected when the repo's files are known.
460
+ - No fabricated survey stats or global tutorial rankings.
461
+ - Uncertain compiler edges flagged for **repro + `tsc`** rather than speculation.
462
+
463
+ ---
464
+
465
+ ## Optional citations (human-facing verification only)
466
+
467
+ Use these when the user requests links or when double-checking rare compiler or typings wording—not as a prerequisite to implement everyday code.
468
+
469
+ | Topic | URL |
470
+ |-------|-----|
471
+ | Google TypeScript Style Guide (full text embedded as **§C1–§C15**) | https://google.github.io/styleguide/tsguide.html |
472
+ | `gts` (Google TypeScript opinionated toolchain) | https://github.com/google/gts |
473
+ | TypeScript Handbook (intro) | https://www.typescriptlang.org/docs/handbook/intro.html |
474
+ | Handbook index | https://www.typescriptlang.org/docs/handbook/ |
475
+ | TSConfig reference | https://www.typescriptlang.org/tsconfig |
476
+ | TypeScript release notes | https://devblogs.microsoft.com/typescript/ |
477
+ | Playground | https://www.typescriptlang.org/play |
478
+ | typescript-eslint — getting started | https://typescript-eslint.io/getting-started/ |
479
+ | typescript-eslint — shared configs | https://typescript-eslint.io/users/configs |
480
+ | typescript-eslint — rules | https://typescript-eslint.io/rules/ |
481
+ | Biome | https://biomejs.dev/ |
482
+ | Prettier | https://prettier.io/docs/en/ |
483
+ | React — TypeScript | https://react.dev/learn/typescript |
484
+ | React TypeScript Cheatsheet (community) | https://react-typescript-cheatsheet.netlify.app/ |
485
+ | Node.js — Introduction to TypeScript | https://nodejs.org/learn/typescript/introduction |
486
+ | Node.js API — TypeScript | https://nodejs.org/api/typescript.html |
487
+ | DefinitelyTyped | https://github.com/DefinitelyTyped/DefinitelyTyped |
488
+ | Effective TypeScript (book site) | https://effectivetypescript.com/ |
489
+ | MDN — JavaScript (TS erases to JS) | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference |
490
+ | Stack Overflow Survey (technology) | https://survey.stackoverflow.co/2025/technology |
491
+ | State of JS | https://2025.stateofjs.com/en-US/resources/ |