Eidos in the TypeScript Ecosystem
The GoF design patterns are not outdated. The problems they solve are still real. They just need to be adapted to the way we write TypeScript today: composable, functional, without classes or inheritance. Even the Singleton, often criticized as an anti-pattern in OOP, becomes harmless in functional TypeScript where it's just a module-level const.
Pithos is the only TypeScript library that provides all 23 GoF design patterns in a functional style. Some libraries teach them as OOP examples. Others solve one or two patterns in isolation. Eidos is the first to cover all 23 with a unified, composable, framework-agnostic API. This page explains why that matters.
What Exists Today
Design pattern resources in JS/TS fall into three categories. Each solves part of the problem. None solves all of it.
-
Educational repositories.
Projects like refactoring.guru, torokmark/design_patterns_in_typescript or design-patterns-for-humans cover all 23 patterns, but as examples you cannotnpm install. And they all teach patterns through OOP (classes and inheritance), while modern TypeScript stacks increasingly favor composable, functional approaches. -
Specialized libraries.
The ecosystem offers excellent single-pattern solutions: RxJS, mitt, or nanoevents for Observer; XState or Robot for State machines; Immer for Command/undo-redo; Ramda for function composition. Some libraries like Zustand combine several patterns (State, Observer, Command) but remain tied to React. Each covers its niche well, but none aims to provide a complete, framework-agnostic set of patterns. -
FP ecosystems.
Libraries like fp-ts, Effect, or purify-ts provide functional abstractions that indirectly overlap with some GoF patterns. But none set out to cover all 23. The coverage is incidental.
Where Eidos Fits
Eidos sits in a space none of the three categories above occupy: a production-ready, tree-shakable library that covers every GoF pattern with a consistent functional API.
The Fragmentation Problem
Covering just five patterns with specialized libraries means five npm install, five API styles, five documentation sites, and five mental models for what are, at the core, related structural ideas:
npm install rxjs # Observer
npm install xstate # State
npm install ramda # Decorator / composition
npm install immer # Memento / Command
npm install iter-tools # Iterator
This is not a criticism of these libraries, they are excellent at what they do. But a project that needs several patterns pays for the fragmentation in cognitive load, bundle weight, maintenance surface, and supply chain risk: each dependency is a potential vulnerability.
What Eidos Does Differently
Framework-Agnostic
Most specialized libraries are tied to a specific ecosystem. RxJS is deeply integrated with Angular. Zustand is designed for React. XState has framework-specific bindings. If you switch framework, or if you work on a backend Node.js project, these libraries either don't apply or bring unnecessary coupling.
Eidos has no opinion on your framework. It produces plain functions and plain data. You can use it in React, Angular, Vue, Svelte, a CLI tool, a serverless function, or a vanilla TypeScript project. The patterns work the same way everywhere because they depend on nothing but TypeScript itself.
One Import Path, One Philosophy
Every pattern follows the same conventions: functions return plain data, state is immutable, configuration uses typed records, composition uses higher-order functions.
import { createStrategies } from "@pithos/core/eidos/strategy/strategy";
import { createMachine } from "@pithos/core/eidos/state/state";
import { createChain } from "@pithos/core/eidos/chain/chain";
import { createObservable } from "@pithos/core/eidos/observer/observer";
import { createBuilder } from "@pithos/core/eidos/builder/builder";
No classes. No inheritance. No abstract methods. Same mental model everywhere.
Honest About What the Language Already Does
Eidos deliberately exports all 23 patterns, including the five that TypeScript makes trivial. These five are marked @deprecated, which serves two purposes: the library remains a complete, homogeneous reference for all GoF patterns, and developers searching for "factory method" or "visitor" in their IDE get immediate guidance toward the idiomatic alternative instead of a class-based implementation.
| Pattern | What your IDE shows you |
|---|---|
| Factory Method | "Pass the factory function as a parameter. This is dependency injection." |
| Bridge | "Pass the implementation as a function parameter." |
| Facade | "Write a function that calls other functions." |
| Visitor | "Use a switch on a discriminated union." |
| Interpreter | "Define a discriminated union AST and a recursive eval function." |
Shared Infrastructure with Pithos
Four patterns are re-exports from Arkhe, with zero additional bundle weight:
| Pattern | Arkhe function |
|---|---|
| Prototype | deepClone() |
| Singleton | once() |
| Flyweight | memoize() |
| Proxy | memoize(), throttle(), debounce(), lazy(), guarded() |
Every Pattern Has a Live Demo
Each pattern comes with a dedicated page that includes the problem it solves, the Eidos solution, and an interactive demo you can try in the browser, with its source code downloadable.
Discover the demos

State
Finite state machine with typed transitions and events. A tennis scoreboard for Roland Garros where the Deuce/Advantage loop is encoded in transitions, not conditionals.

Strategy
Swap algorithms at runtime by key. A cosmetics e-shop pricing calculator with interchangeable discount strategies (Standard, Club, Seasonal, Coffret).
createStrategies(), safeStrategy(), withFallback(), withValidation()

Observer
Typed pub/sub event emitter. A stock trading dashboard where chart, alerts, and portfolio react independently to price changes.

Command
Encapsulate actions with undo/redo. A Kanban board where every drag is a reversible command with human-readable history and replay.

Iterator
Lazy sequences with Option-based next(). A Pokédex browser with three interchangeable traversal strategies over 151 Pokémon.

Builder
Step-by-step construction with a fluent API. A chart builder where toggling steps updates the visualization in real-time.

Decorator
Stack behaviors without modifying the core function. A DNA analysis pipeline where you toggle quality filter, cache, retry, and timing decorators.

Chain of Responsibility
Pipeline of handlers that can pass or short-circuit. An HTTP middleware simulator with toggleable auth, rate-limit, validation, and logging.

Mediator
Centralize communication between components. A DGAC flight dashboard where weather, flights, and runway panels communicate through a typed event hub.

Memento
Capture and restore state snapshots. A photo editor with filters where each change creates a thumbnail snapshot you can jump to.

Template Method
Define an algorithm skeleton with overridable steps. A resume builder where Developer, Designer, and Manager profiles override specific steps.

Abstract Factory
Create families of related objects. A cross-platform UI kit where switching iOS/Android/Web re-skins the entire form at once.

Adapter
Make incompatible APIs work together. A map app that normalizes two French open data APIs (EV charging + fuel stations) into one uniform format.

Proxy
Control access with caching, rate-limiting, and fallback. A simulated LLM API where cache hits save money and rate limits protect the provider.

Singleton
Lazy initialization, same instance on every call. Three services (Database, Cache, Logger) where first request is slow and subsequent ones are instant.

Prototype
Clone objects without shared references. A config editor where deep clone keeps the original untouched while shallow copy leaks mutations.

Flyweight
Share common state to reduce memory. A text editor where style objects are pooled via memoize, showing 96% memory savings.

Factory Method
Delegate creation to injected functions. A notification sender where the same sendNotification() call produces Email, SMS, Push, or Slack notifications.
Pattern absorbed by the language (dependency injection)

Visitor
Add operations without modifying objects. An email builder where the same block list produces Preview, HTML, Plain Text, or Accessibility Audit output.
Pattern absorbed by the language (switch on discriminated union)

Bridge
Decouple two axes that vary independently. A music visualizer with 3 audio sources x 5 renderers = 15 combinations from one function call.
Pattern absorbed by the language (pass functions as parameters)
Eidos vs Dedicated Libraries
For some patterns, a dedicated library goes deeper than Eidos. This is by design: Eidos covers the 80% case. When you need the full framework, use the framework.
| Pattern | When Eidos is enough | When to reach for a dedicated lib |
|---|---|---|
| Observer | Simple typed pub/sub | Complex stream processing (RxJS) |
| State | Finite state machine with typed transitions | Hierarchical statecharts, actors, visualizer (XState) |
| Iterator | Lazy sequences, basic operators | Extensive async iteration operators (IxJS) |
| Command | Undo/redo with action history | Full state management with devtools (Zustand) |
| Decorator | before/after/around hooks | Full FP utility library (Ramda) |
Patterns Where No Alternative Exists
Eight patterns have no standalone functional TypeScript library. The only options today are manual implementation or Eidos:
- Abstract Factory
- Builder (generic, not domain-specific)
- Chain of Responsibility (standalone, not framework middleware)
- Adapter (typed function wrapper)
- Mediator (typed event hub)
- Memento (snapshot history)
- Template Method
- Composite (typed tree with fold/map)
Eidos Complements, It Doesn't Replace
Eidos is not competing with technology-specific solutions. If your framework provides a reactive primitive (RxJS Observables, Angular Signals, Solid signals), use it. Eidos steps aside. If you need full statecharts with a visual inspector, XState is the right tool. If you need a complete effect system with structured concurrency, Effect is the right tool.
Eidos fills the gaps between these specialized solutions: the patterns that have no dedicated library, the patterns you would otherwise implement by hand, and the patterns that are so simple in functional TypeScript that all you need is a one-line reminder in your IDE.
You can use Eidos alongside any of these libraries. Import one pattern or twenty, each is independently tree-shakable, and patterns that overlap with Arkhe carry zero additional weight.
Further Reading
- Eidos module guide: philosophy, categories, and quick examples
- Eidos API reference: all 23 patterns with full documentation
- Pithos vs Effect: modular ecosystem vs full effect system
- Comparison Overview: when to use each Pithos module


