Language · We run it ourselves
The language of the browser, run on the server too — used here without a type layer on top of it.
We write most things in TypeScript. One of the larger applications we have built is plain JavaScript throughout and was never going to be anything else, and saying why is more useful than pretending every project got the same answer.
01
A type layer is a build step, and a build step is a thing that can disagree with itself. The lease calculation at the centre of that application is loaded by two different runtimes — a bundler and plain node inside build scripts — and it deliberately has no imports and no framework, so that a single file can be the only copy. Adding a compile stage between those two consumers buys checking and costs the property that made the arrangement safe.
02
Where the invariants are enforced by assertions against an external source of truth, a type system is checking a different question. Types confirm that the code agrees with itself; they cannot confirm that a monthly payment agrees with a commercial offer sheet. On that project the build fails on the second question, which is the one that was actually going wrong.
03
The honest trade is refactoring. Renaming something across four hundred files without a compiler is slower and more dangerous, and we do not pretend otherwise — what compensates is that the parts where a mistake is expensive are covered by assertions that run on every build rather than by a hope that everyone reads carefully.
04
It also removes a class of onboarding cost that is real on a client's team. A codebase somebody else has to maintain after us is a different object from one we keep, and a stack with fewer moving parts is easier to hand over — which is a legitimate input to the decision rather than an excuse.
05
Where we do reach for types, it is for the same reason everywhere: the type is the place an editorial rule lives. This site's own stack ledger will not compile an entry without evidence. That is not a bug filter; it is a promise made structural, and it needs a type system to exist at all.
An entry that cannot point at something you can open, run or read does not compile. That is a property of the type, not a promise in a paragraph.
Invariant
This is defensible on a project where the risky invariants are external and checkable at build time, and indefensible where they are internal and structural. A large domain model with many collaborating modules and a team that rotates is exactly where a compiler earns its keep, and choosing plain JavaScript there is not minimalism, it is deferred cost.