Typescript Best Practices

by cursorccb5507cec15No license10K starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated today

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

Instructions onlySoftware Development
AI-generated overview

TypeScript coding rules covering type modeling, narrowing, validation and testing discipline.

What it does
This skill supplies a rule table of TypeScript best practices for reading or editing .ts and .tsx files. It covers discriminated unions, branded types, constructive modeling, unknown over any, schema-first validation, narrowing order, exhaustiveness checks, satisfies over as, boundary parsing, schema-derived types, object arguments, real tests and structured telemetry. It points to a reference file of examples and defers to separate principle skills for type-system and boundary discipline.
When to use it
Use it when reading or editing any TypeScript or TypeScript React file, so that type modeling and validation follow the same conventions. It is aimed at code work where types, casts, guards or boundary parsing are involved.
Requirements
No scripts; instructions only. It expects the repository's runtime schema library to be available for schema-first validation and refers to separate principle skills.

TypeScript best practices

Apply the type-system-discipline principle skill first.

RuleSummary
Discriminated unionsModel variants with a kind literal discriminant so impossible states can't be represented. No optional-field bags.
Branded typesBrand primitives with & { readonly __brand: "X" } so they can't be mixed up. Validate once at the boundary.
Constructive modelingBuild 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 typeKeep 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 anyExternal data is unknown.
Schemas before guardsBefore 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 castsEvery as is a runtime crash waiting. Cast only after validation.
Narrowing hierarchyDiscriminant switch > in operator > typeof/instanceof > user-defined type guard > as.
Type guardsMust 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.
ExhaustivenessInline const _exhaustive: never = x; in default arms so the compiler errors when a new variant is added.
satisfies over asValidates the value without widening literal types.
Boundary validationParse 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 typesReach for Pick/Omit/Parameters/ReturnType/Awaited/typeof before declaring a new interface.
Object argsPass objects, not positional, so argument order is self-documenting. Skip on hot paths (per-frame render, tokenizers, parsers).
Real testsDon'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 telemetryPrefer structured logger diagnostics with enough context to debug from an id. No console.log in shipped code.

Examples: references/patterns.md.

Source and attribution

Source:cursor/pluginsinpstack/skills/typescript-best-practicesat commitccb5507

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal