fp-ts
Giulio Canti‘s library for writing Haskell-style functional code in TypeScript.
The stated goal, verbatim: to “empower developers to write pure FP apps and libraries built atop
higher order abstractions.” It supplies “popular patterns and reliable abstractions from typed
functional languages in TypeScript”, borrowed explicitly from haskell, PureScript and Scala —
Option, Either, Task, and the type classes over them (Functor, Applicative, Monad, Traversable).
11.5k stars, MIT, version 2.x.
T1 — first-party documentation and repository.
The distinctive part: higher-kinded types that the language does not have
fp-ts’s own docs call this its distinctive feature. A type class like Monad must abstract over a
type constructor — over Option itself, not over Option<number>. TypeScript generics only
abstract over types, so Monad<F> where F is “something that takes a type” is not expressible.
The workaround is defunctionalization, and the docs name its source: the paper
Lightweight higher-kinded polymorphism (Yallop & White, FLOPS 2014), written for
OCaml, which has the same gap. Type application becomes an ordinary type HKT<F, A>, and each
constructor gets a brand — an empty marker standing for Option as a thing that can be applied.
Injection and projection functions move between the real type and its encoded form.
It works, and the paper is candid about the price (recorded on that page): the checker cannot rule out ill-kinded encodings, because to it the brands are just types. What TypeScript gives back is the error messages, which is the complaint every practitioner account of fp-ts arrives at.
The ending
The repository’s own notice: fp-ts is merging into the Effect-TS ecosystem, with Effect described as “the successor to fp-ts v2”, and Canti joining the Effect organization. Read against effect‘s homepage, this is a change of argument and not only of maintainer. fp-ts argued from the abstractions down — here are Haskell’s structures, TypeScript can hold them. Effect argues from production requirements up — here is typed failure, dependency injection and tracing, and the functional machinery is how they are delivered. The abstraction-first framing is the one that stopped.
Worth stating plainly, since both pages are first-party and neither says it: nothing here shows the library approach failed on the merits. A merge is a decision by the people involved, and this wiki has no source on why they made it.
Related
effect · lightweight-hkt · functional-programming · typescript · haskell · ocaml · type-system · giulio-canti · synthesis