~/langs $ bunx tsc --strict // 0 errors (at compile time, anyway)
CTYPESCRIPT
the illusionist · a great type system on a cursed lineage
[01] ORIGIN
JavaScript was designed in ten days in 1995. TypeScript is twelve years of Microsoft's best compiler people apologizing for that, brilliantly.
Anders Hejlsberg (Turbo Pascal, Delphi, C#) shipped TypeScript in 2012 with a thesis nobody believed at the time: you can bolt a sound-enough, gradual, structural type system onto JavaScript without changing the runtime, and the entire industry will adopt it. The entire industry adopted it. The types exist only at compile time, the runtime stays the ten-day language underneath, and the gap between those two facts is where both the magic and the lies live. This site is TypeScript on Bun; the language is not the problem. The world around it is.
| creator | Anders Hejlsberg, Microsoft, 2012 |
| paradigm | gradually-typed JavaScript; the types are advice |
| memory | GC'd, far away, not your concern (that's the problem) |
| deps | npm: a supply-chain attack with a registry attached |
| famous users | everyone with a frontend, which is everyone |
| my use | this very site: one Bun.serve() call, zero config |
[02] WHAT IT GETS RIGHT
Discriminated unions plus control-flow analysis: check the tag and the compiler reshapes the type in your hands, branch by branch. The best everyday type UX in the industry, in any language, and it isn't close.
Shape matters, not lineage. If it has the fields, it fits the type: the way data actually behaves at a protocol boundary, formalized instead of fought with class hierarchies.
Write the code; the compiler works out the types and the hover tooltip knows more about your data than you do. Annotations only where they earn their keep.
The only runtime sitting in every browser tab and pocket on earth. When the deliverable is "runs on whatever the user has", there is no second option, so it's good that the type system is this nice.
Rename one .js file at a time and tighten as you go. Types arrive without a rewrite, which is the only reason any large JavaScript codebase ever got them at all.
One fast tool where node + npm + webpack + jest used to be. This site is one Bun.serve() call serving HTML that imports TypeScript directly. The toolchain pain is optional now; most people just haven't noticed yet.
[03] THE CODE
type NostrEvent = | { kind: "note"; content: string } | { kind: "zap"; sats: number } | { kind: "dm"; ciphertext: string }; function handle(e: NostrEvent) { switch (e.kind) { case "note": return render(e.content); // e is the note arm case "zap": return thank(e.sats); // e is the zap arm case "dm": return decrypt(e.ciphertext); // e is the dm arm } // add a kind tomorrow and strict mode flags every // switch that forgot about it. that part is great. }
The illusion at its best: the compiler walks the branches with you and the types
narrow like a good argument. Just remember it's all erased at runtime; one
as any from a dependency and the whole spell breaks silently.
[04] THE BAD
// status effects
- NODE_MODULES GRAVITY WELLthe dependency tree has the mass of a small moon and its own weather. The rap sheet is mostly an npm rap sheet, and that is not a coincidence.
- COSTUME BREAKS AT RUNTIMEthe types are an illusion the compiler maintains for your benefit; at runtime it is all JavaScript, and
anyis one keystroke of surrender away. Validation at the boundary is on you. - FRAMEWORK CHURNthe framework of the week has a half-life of eighteen months, and the migration guide assumes you already migrated.
- TYPE GOLFthe type system is Turing complete and some of your coworkers know it. Conditional mapped template-literal types can model anything, including problems you didn't have.
- THE FLOOR IS STILL JS0.1 + 0.2,
==,this, date handling: the ten-day foundation leaks through every abstraction built on it. The illusionist is brilliant; the stage is cursed.
[05] VERDICT
C tier, and the C is for "circumstances". Best-in-class types, held hostage by the world they live in.
Use it for everything that must run in a browser, which is the one arena where it has no rival; use Bun and skip the toolchain tax, like this site does. Keep the dependency tree shallow and vendored, validate at the boundaries, and it's genuinely pleasant. Just don't mistake the costume for armor: when the work is a server you own, Odin is faster, simpler and honest about memory; when it holds keys, Rust.
// the type system deserves a better runtime. it knows. you can tell it knows.