Skip to main content

typescript-best-practices

TypeScript best practices. Use when reading or editing any .ts or .tsx file.

Source facts

Repository
cursor/plugins
Last source activity
September 8, 2026 at 00:00
Detected SKILL.md language
English
Stars
9,052
Forks
849

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
typescript-best-practices
description
TypeScript best practices. Use when reading or editing any .ts or .tsx file.
paths
["**/*.ts","**/*.tsx"]
disable-model-invocation
true
# TypeScript best practices Apply the **type-system-discipline** principle skill first. | 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 the boundary. | | Constructive modeling | Build the shape so the illegal value can't be constructed. `[T, ...T[]]` for non-empty, `[T, T][]` for even length, `start` plus `duration` for a range. Not a runtime guard, not a wish for refinement types. | | Simplest total type | Keep `T[]` while every operation on it stays total. Strengthen to `NonEmpty<T>` only where the loose type forces `!`, a cast, or a "should never happen" throw. | | `unknown` over `any` | External data is `unknown`. | | Schemas before guards | Before hand-writing a property-by-property type guard, use the repository's runtime schema library and infer the type from the schema, such as `z.infer`. | | 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 | Parse where data crosses in, into a named domain type. `Record<string, unknown>` (however spelled) stops at that parse. 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`.
View on GitHub