Skip to main content

TypeScript Design Patterns

This guide rereads the GoF design patterns from one angle: what they look like when you write them in modern TypeScript.

About this guide

Most design patterns were organized around languages that put classes and inheritance at the center. TypeScript has first-class functions, discriminated unions, and structural subtyping, and there are places where you can reach the same goal without a class hierarchy.

So alongside explaining each pattern, every chapter judges whether that pattern is still needed in TypeScript. The judgment never stops at "language features can replace it" — it always lays out the conditions under which writing the pattern as a class still pays off.

This guide is written for readers who have written classes and interfaces in TypeScript and want more design options. The syntax itself is covered in the TypeScript Guide, and the norms for code quality in Clean Code Guide.

How each chapter is structured

Every pattern chapter uses the same five sections. That is a promise to keep facts and editorial judgment from mixing.

SectionWhat goes in it
The problem this pattern set out to solveThe intent the pattern defined and the conditions it applies under, with sources
Writing it straightforwardly with classesA TypeScript implementation that follows the pattern as written
Replacing it with language featuresThe language features you can reach for instead, with sources from specs and documentation
How this series judges itThis is the only editorial judgment. It lays out when language features suffice and when to keep writing a class
How this relates to existing articlesLinks to existing articles that cover the same subject

Each judgment is one of three: "language features can replace it," "conditional," or "a class implementation is recommended." A judgment is this guide's position rather than a fact, so it comes with its grounds and with what would overturn it.

Creational patterns

ChapterPatternWhat it covers
01SingletonHow far the single instance an ES module gives you reaches, and where that stops
02Factory Method and Abstract FactoryThe conditions under which creation can move into a function
03BuilderWhen a literal is enough, and when the type expresses staged requirements

Structural patterns

ChapterPatternWhat it covers
04AdapterThe boundary structural subtyping removes
05DecoratorWhy it is a different concept from TypeScript's Decorators syntax
06ProxyWhy it is a different concept that happens to share a name with the built-in Proxy
07CompositeRepresenting a tree with a recursive discriminated union

Behavioral patterns

ChapterPatternWhat it covers
08StrategyHow far passing a function alone gets you
09ObserverHow much EventTarget and AbortSignal cover
10StateForbidding invalid transitions in the type system
11Template MethodFixing the skeleton through inheritance versus injecting hook functions
12IteratorThe iteration abstraction the language absorbed
13VisitorThe role the exhaustiveness check takes over
14Chain of ResponsibilityThe middleware shape, and passing context through types

A pattern outside GoF, and the wrap-up

ChapterContents
15Repository. A pattern that comes from PoEAA rather than GoF, covered from the angle of expressing it in types
16Short takes on the patterns that got no chapter, and the full list of judgments

Patterns without a chapter of their own

Covering all 23 patterns at the same density would break the length, so this guide narrows to the ones with the most room for discussion from a TypeScript angle. The following eight get no chapter of their own and are covered briefly in the summary. This selection is this guide's editorial judgment.

PatternWhy it got no chapter of its own
PrototypeIts subject is the means of copying, and there is not enough to argue about to fill a chapter
FacadeIt centers on narrowing what you expose, which leans into module design
CommandRepresenting operations as data overlaps with the Visitor chapter, and existing articles cover it in a different context
BridgeSeparating abstraction from implementation tends to overlap with Strategy and Adapter
FlyweightIts subject is cutting memory through sharing, which leans into runtime behavior
MediatorPlacing a mediator raises few points specific to TypeScript
MementoSaving and restoring state ends up reaching for the same tools as Prototype
InterpreterIts subject is evaluating a syntax tree, which overlaps with what the Visitor chapter covers