TypeScript's value is not immediately obvious on a small codebase with a single developer. It becomes undeniable as the codebase grows past 10,000 lines, as new engineers join the team, and as features built months ago need to change. These are the practices that unlock that value.
Always Use Strict Mode
Set "strict": true in your tsconfig.json from day one. Strict mode enables null checks, implicit any detection, and several other checks that together eliminate a large class of runtime errors. Retrofitting strict mode into an existing codebase is painful. Starting with it is free.
Prefer Type Inference Over Explicit Annotation
TypeScript infers types remarkably well. Annotating every variable explicitly creates noise and maintenance burden. Annotate at boundaries — function parameters, return types, exported APIs — and let the type system infer everything else.
Use Discriminated Unions for State Modelling
Instead of optional fields that may or may not be present, model state explicitly with discriminated unions. A Result<T> type with a discriminant property forces consumers to handle both success and error cases, eliminating a class of bugs that null checks miss.
Narrow Types, Do Not Assert
Type assertions (as SomeType) bypass the type checker and push bugs to runtime. Use type guards and narrowing instead — conditional checks that the TypeScript compiler can verify and use to narrow the type in subsequent code.
Extract Reusable Types to a Shared Module
Types that appear in multiple files should be defined once and imported everywhere. Duplicated type definitions drift apart over time and cause silent incompatibilities. A types/ or shared/ directory for domain types keeps the type system coherent as the codebase grows.
Building with TypeScript and want a team that gets it right?
Asquarify engineers are TypeScript-first across all projects. Talk to us about building software that stays maintainable as it grows.
Get in touch