Enforces a tight set of TypeScript patterns that treat the type system as a proof assistant rather than documentation. Every rule here exists to close a gap where TypeScript would otherwise let you lie to yourself: discriminated unions over optional fields, branded primitives to prevent ID mixups, unknown for external data, and exhaustiveness checks that break the build when you add a variant. The narrowing hierarchy and type guard rules are especially useful if you're tired of as casts hiding bugs. Also pushes object parameters for readability and real tests over mocks, which is opinionated but defensible. If you want TypeScript to actually catch your mistakes instead of rubber stamping them, this is a solid foundation.
npx -y skills add cursor/plugins --skill typescript-best-practices --agent claude-codeInstalls into .claude/skills of the current project.
Apply the type-system-discipline principle skill first; this skill grounds it in TypeScript syntax.
| Rule | Summary |
|---|---|
| Discriminated unions | Model variants with a kind literal discriminant so impossible states can't be represented. No optional-field bags. |
| Branded types | Brand primitives with & { readonly __brand: "X" } so they can't be mixed up. Validate once at creation. |
unknown over any | External data is unknown. any disables type checking everywhere it touches. |
No as casts | Every as is a runtime crash waiting. Cast only after validation. |
| Narrowing hierarchy | Discriminant switch > in operator > typeof/instanceof > user-defined type guard > as. |
| Type guards | Must verify the claim. A lying guard is worse than as because the bug hides behind a name that says it's safe. Name them isX or hasX. |
| Exhaustiveness | Inline const _exhaustive: never = x; in default arms so the compiler errors when a new variant is added. |
satisfies over as | Validates the value without widening literal types. |
| Boundary validation | Validate where data crosses in; trust types inside. See the boundary-discipline principle skill. |
| Schema-derived types | Reach for Pick/Omit/Parameters/ReturnType/Awaited/typeof before declaring a new interface. |
| Object args | Pass objects, not positional, so argument order is self-documenting. Skip on hot paths (per-frame render, tokenizers, parsers). |
| Real tests | Don't mock what you can run. Prefer the framework's real test primitives with leak/disposable checks, and verify UI in a running build. Mock only what you can't run locally. |
| Structured telemetry | Prefer structured logger diagnostics with enough context to debug from an id. No console.log in shipped code. |
Examples: references/patterns.md.
juliusbrussee/caveman
mattpocock/skills
obra/superpowers
forrestchang/andrej-karpathy-skills
vercel-labs/skills