1. Introduction
tcm-ts keeps your TypeScript in a codebase instead of a folder of files. You write code in ordinary .ts
files, as always; when it typechecks, you add it, and each function, type and constant is stored by a hash of
its code. From then on, names are just labels on those hashes.
That one change has a lot of consequences, and they're the reason to use it:
- Renaming is free.
tcm mv lib.parse lib.parseConfigchanges a label. No code is edited, nothing breaks, every use shows the new name. - Changes carry through, or tell you.
tcm updatere-checks everything that uses what you changed. Whatever still typechecks follows along automatically; whatever doesn't is put on a todo list, with the reason. Nothing is ever half-updated. - Nothing to build. Node runs the stored code directly (JSX is compiled as it loads), and a production build is
named by the app's hash and reused. Tests and lint findings are cached by hash: a test only runs again if its
code, or something it calls, changed, and results travel with
tcm pushandpull, so another machine doesn't run them again. - Less to manage. Apps bundle only what they reach, so there's no dead code to eliminate; definitions that
refer to each other are stored together, so there are no circular imports; and one codebase holds any number of
apps and packages, with no
package.jsonto maintain and no monorepo tooling. - History by meaning.
tcm diffshows what changed in your code, not in your files: reformatting and renaming locals aren't changes, and renames are recognised as renames. Every change can be undone. - Docs that can't go stale. Links and examples in your doc comments are code too: they follow renames and updates, and examples are run, so a broken one is reported.
- Web apps without an API layer. Write a function that reads a database and call it from browser code. tcm
works out what runs on the server and what runs in the browser, and connects them, with no routes, fetch calls
or
"use server". Because calls go by hash, a page can never call the wrong version of the server, and deploying and rolling back are moving a name.
Each of these, where it stops, and the test that proves it: what tcm does away with.
It's Unison's codebase model, brought to plain TypeScript: no new language, no new syntax, and the code runs on Node as it is.
1.1 How it's different
One small shop app, both ways. As a JavaScript project, its code is in files, in folders, in packages, and each tool reads the files to make what it makes:
As a codebase, each value, type and function is a definition of its own, and an output is what it starts from reaches:
When one value changes, a project checks, tests, bundles and ships again every file that imports its file. A codebase redoes only what reaches it:
Press a diagram to see it full size.
1.2 What it looks like
// scratch.ts
/** Square a number. */
export const square = (x: number): number => x * x;
square(12);
$ tcm check
scratch.ts
+ new square : (x: number) => number
7 │ square(12)
⧩ 144
$ tcm add
+ new square : (x: number) => number
square(12) on its own line is a watch expression: tcm runs it and shows its value, like a REPL inside your
file. square itself is now in the codebase, and any other file can use it with
import { square } from "#codebase".
1.3 Where next
- Install tcm-ts and set up a codebase.
- Follow the tutorial, your first codebase, about fifteen minutes.
- Or build a small web app and see the server and browser parts fit together.
- Look at the polls example, a complete app that uses most of tcm's features.