typescript
Installation
SKILL.md
TypeScript
House conventions for TypeScript 5+. Apply them to code you are writing or changing — don't refactor untouched files to match unless asked.
Conventions
- Model the domain in types, not in checks. Branded types (
type UserId = string & { readonly __brand: 'UserId' }) and discriminated unions push errors to compile time, where they cost nothing. A runtime guard catches the same bug in production. - Discriminated unions for anything with states — request lifecycles, form state, parse results. The compiler then forces every state to be handled, so a new variant surfaces as an error rather than a silent fallthrough.
satisfiesoveras.satisfiesvalidates against a type while keeping the narrow inferred literal;asthrows the check away. Reach forasonly when you know something the compiler cannot, and say why in a comment.- Const objects over
enum.as constobjects are plain values with no emit and no nominal-typing surprises;enumgenerates runtime code andconst enumbreaks underisolatedModules. anyis a bug report. Useunknownand narrow. Ifanyis genuinely unavoidable at a boundary, isolate it in one adapter function rather than letting it spread through call sites.- Separate type-only imports (
import type { … }). Bundlers erase them cleanly; mixed imports can keep a runtime dependency alive that you meant to drop. - Let inference work. Annotate exported/public signatures and let everything internal infer — over-annotation is noise that drifts from the real type.
- Ship
.d.tsfor anything consumed as a library (declaration: true). Without it, consumers fall back toanyand your type work stops at the package boundary. - Monorepos: project references +
composite. Incremental builds only rebuild what changed; a single flattsconfigrecompiles the world on every edit.
The two idioms worth showing
Exhaustiveness only actually holds if you force it. A switch over a union compiles fine when a new variant appears — assertNever is what turns that into a build error at every site that needed updating: