TypeScript in Practice
Using the type system to prevent real bugs rather than to decorate code. Generics, narrowing, domain modelling, validation at the boundary, async concurrency, module resolution, dependencies, testing, builds and CI — the parts of TypeScript that decide whether a codebase stays pleasant.
Start courseWhat you will cover
- Strict Mode and the Options That MatterWhat each strict flag actually catches, which additional options are worth the friction, and how to turn strictness on in a codebase that was not written for it.30 min
- Generics and Reusable TypesWriting a function or type that works for many types without losing the specific one, constraints that keep it honest, and the generic parameter that should have been a plain argument.30 min
- Narrowing in DepthType guards, discriminated unions, and exhaustiveness checks that turn a new case into a compile error instead of a silent fall-through.30 min
- unknown, any, and neverThe three types people misuse most: what each one means, why any disables the compiler far beyond the line it appears on, and what never is telling you when it shows up.30 min
- Modelling Domains with TypesMaking illegal states unrepresentable: replacing boolean flags with unions, encoding invariants in shapes, and letting the compiler enforce rules you were writing comments about.30 min
- Error Handling StrategiesThrowing versus returning a result, typed error unions, keeping error information across boundaries, and choosing one approach so callers do not have to guess.30 min
- Validating Data at the BoundaryAnything crossing into your program is unknown until proven otherwise. Parsing over casting, schema validation, and why a type assertion on API data is a lie with a compile-time blessing.30 min
- Async Patterns and ConcurrencyRunning work in parallel versus in sequence, all versus allSettled versus race, cancelling with an abort signal, and the awaited loop that made everything ten times slower.30 min
- Module Resolution, ESM, and CJSWhy an import that looks correct fails at runtime: the two module systems, resolution modes, file extensions, and reading the error instead of guessing at config.30 min
- Project Structure and ReferencesOrganising a codebase that has outgrown one tsconfig: project references, incremental builds, path mapping, and dependency boundaries the compiler enforces.30 min
- Dependencies and Their Type DefinitionsWhere types come from when they are not in the package, community type packages, versions drifting apart, and typing a library that ships none.30 min
- Utility TypesThe built-in transformations — Partial, Pick, Omit, Record, Required, Awaited and friends — what each is really for, and the point where a chain of them becomes unreadable.30 min
- Testing TypeScriptRunning tests against typed code, typing test helpers and fixtures without fighting them, and asserting on types themselves so a refactor cannot quietly widen an API.30 min
- Linting and FormattingType-aware lint rules that catch what the compiler allows, separating formatting from correctness, and configuring both so they never disagree.30 min
- Building and BundlingCompiling versus bundling, emitting declaration files, source maps that make production stack traces readable, and choosing an output that suits who consumes it.30 min
- Runtime Versus Compile TimeTypes are erased before your code runs. What that means for validation, reflection and generics, and the checks people expect the type system to perform at runtime.30 min
- TypeScript in CIType checking as a required gate, keeping it fast as the codebase grows, caching and incremental builds, and failing on the errors that matter.30 min