Spokes.wiki Search About
Tech Article source ↗ source url updated Wed Aug 12 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

Records and Tuples (TC39, withdrawn)

The proposal that would have given JavaScript, and therefore typescript, deeply immutable values as primitives, and the record of its death. Record was an immutable object-like value written #{ x: 1, y: 2 }; Tuple was its array counterpart, #[1, 2, 3]. Both were to be primitives, compared by value rather than by reference.

Withdrawn. Consensus to withdraw was reached at the TC39 plenary of 14 April 2025; the notice was posted to the proposal repository by acutmore on 15 April 2025, and the repository was archived the same day. The proposal had been at stage 2. The stated reason: it “was unable to gain further consensus for adding new primitives to the language.” Reporting around the plenary attributes the deadlock to unrealistic performance expectations for value-compared primitives. A narrower successor, composites, is named in the withdrawal thread — objects rather than new primitives.

T1 for the withdrawal facts — the committee’s own repository. The performance rationale comes from plenary summaries and press rather than the notice, and is marked as such.

Why this decides what “pure FP in TypeScript” can mean

Immutability is not a library feature in the languages that take it seriously. clojure puts persistent immutable structures in the data model, which is what makes its concurrency story work at all. haskell makes immutability the default and mutation the annotated exception. Both are language-level guarantees, enforced at runtime by construction.

TypeScript’s readonly is a compile-time annotation on a mutable object, and it disappears with every other type when the compiler strips them (typescript). Nothing at runtime stops a cast, a third-party library, or plain JavaScript from writing through it. Object.freeze is shallow and costs a check on every access. Records and Tuples were the route to the real thing, and the committee declined to take it.

The consequence for effect and fp-ts is direct. Both can give you typed errors, composition, and Haskell’s abstractions — the parts a type layer can encode. Neither can give you a value the runtime will refuse to mutate, because the host language has no such value and, since April 2025, has no accepted plan to acquire one.

The pattern this is a third instance of

This wiki now holds three separate walls in front of the same goal, and they are of different kinds:

  1. No higher-kinded types: a type-system gap, worked around by encoding (lightweight-hkt, fp-ts).
  2. No effect tracking: worked around by a userland type, Effect<Success, Error, Requirements> (effect).
  3. No immutable values: not worked around, because a compile-time type layer cannot manufacture a runtime guarantee.

The first two are library problems. The third is a language decision, and it was taken by a standards committee that does not answer to the functional-programming community at all — which is the sharpest example this spoke has of language-governance setting the ceiling on what a paradigm can be in a given language.

typescript · javascript · effect · fp-ts · functional-programming · clojure · language-governance · synthesis