TypeScript for a JavaScript team
TypeScript adds types to JavaScript, checks them before the code runs, and then removes them. Mangrove Market's NestJS APIs and React Native apps are already written in it. This lesson shows what the checker really catches, what it cannot catch, and how to share one set of types between the API and its clients.
By the end you can
- Explain what
tscdoes, and why types do not exist at runtime - Write interfaces, type aliases, unions, literal types and generics, and narrow a union safely
- Use the utility types
Partial,Pick,OmitandRecord, and pickunknownoverany - Set up a strict
tsconfig.jsonand convert a JavaScript module to TypeScript - Validate incoming data with zod and share request and response types between a NestJS API and a client
The everyday picture
At the DC, every carton has a product code and a label: "Soybean oil 2 L, 12 per carton". The receiving team checks the code against the purchase order before anything goes to a shelf. A carton of lentils cannot be shelved as rice, because the scanner refuses it at the door, long before a customer finds it.
TypeScript is that label check for code. You describe what each value is: this is a sale line, its quantity is a number, its payment may be missing. The checker compares every use against the label before the program runs, and stops the build when something does not fit. Then, like labels removed once the stock is on the shelf, the types are taken off: what runs is plain JavaScript. That last part matters. Anything that arrives after the door, such as a request from the internet, has never been checked, and you need a different tool for it.
What tsc does, and what it does not
You write .ts files. The TypeScript compiler, tsc, does two separate jobs. It type-checks: reads every file, works out the type of every value, and reports errors. And it emits JavaScript: it deletes the type annotations, interfaces and type imports, and writes .js files. Compare the two versions of receipt in Build it: the logic is identical, and every type is gone.
Three consequences follow. First, types cost nothing at runtime and cannot slow your app down. Second, types cannot check data at runtime. If a request body says "qty": "2" and your type says qty: number, nothing stops it; the checker never saw that request. Third, the editor uses the same checker while you type, which is where most of the value is: red underlines, autocomplete for every field of a sale, and safe "Rename Symbol" across the project (VS Code essentials).
Node 22.18 and later can also run a .ts file directly, by blanking out the types. That is handy for scripts, but it skips the check completely, and it does not support decorators, which NestJS needs. So the team still runs tsc, or a tool built on it, in the editor, in CI and in the build. TypeScript 7, released in 2026, is a much faster rewrite of the compiler with the same type rules. Tools that call the compiler from code, including the NestJS CLI, still use TypeScript 6 for now, which is what a new NestJS project installs.
Quick check
tsc builds the API with no errors. A request then arrives with "qty": "2", where the type says number. What can catch it?
tsc never sees the request, and the types are erased before the code runs, so no engine checks them either. Only something that runs when the data arrives, such as a zod schema or a validation pipe, can reject it.
tsc checks every use of a value against its type and stops the build on an error. If the check passes, it writes JavaScript with every type removed. Data that arrives at runtime, such as a request body, was never checked, so it needs a runtime validator such as zod.