webdev.complete
🔵 TypeScript Basics
🛡️TypeScript
Lesson 41 of 117
15 min

Why TypeScript?

The contract that lets you refactor without fear.

Picture this: it's Friday, 4:50 PM. You ship a tiny change. Monday morning, support tickets arrive. Somewhere in a callback you wrote three months ago, user.adress (note the typo) silently returned undefined, and the app decided every user lives at "undefined". TypeScript exists so that bug never reaches Friday afternoon. The editor underlines the typo as you write it.

What TypeScript actually is

TypeScript is JavaScript with a type system bolted on at edit-time. You write .ts or .tsx, a compiler (the tscbinary, or your bundler's built-in one) checks your types, and the output is plain JavaScript that runs anywhere JS runs. The types are a layer of metadata for you and your tools. They are not a runtime feature.

The three problems TS solves

  • Silent runtime errors. JavaScript is happy to let you call .toUpperCase() on a number and crash in production. TS refuses to compile that.
  • Refactor fear. In a big JS codebase, renaming a property is a leap of faith. With types, the compiler walks every call site for you.
  • No autocomplete.Without types, your editor can't know what a function returns or what fields an object has. With types, every dot you type is a smart menu.

A real bug TS would have caught

Here's the actual shape of a bug I've seen ship more than once. JavaScript first:

user.js
function greet(user) {
  return "Hello, " + user.name.toUpperCase();
}

// Somewhere far away in the codebase
greet({ username: "ada" });
// Runtime error: Cannot read properties of undefined (reading 'toUpperCase')

That code parses fine. It runs fine in tests where you pass { name: "ada" }. It blows up the moment a caller passes username instead. Now in TypeScript:

user.ts
type User = { name: string };

function greet(user: User) {
  return "Hello, " + user.name.toUpperCase();
}

greet({ username: "ada" });
// ^ Argument of type '{ username: string; }' is not assignable
//   to parameter of type 'User'.
//   Object literal may only specify known properties,
//   and 'username' does not exist in type 'User'.

Same logic, same intent. The TS version refuses to compile until you fix the caller. The error message is dry but it points directly at the typo, with a file and a line number, before the code ever runs.

It's a gradient, not a switch
TypeScript is a superset of JavaScript. Every valid JS file is valid TS (rename it to .ts and it works). You can adopt TS one file at a time and lean on any while you migrate. Strict mode is a destination, not a starting line.

Types are erased at runtime

This is the single most important sentence in this whole chapter: TypeScript types do not exist at runtime. The compiler reads them, checks them, and then deletes them. Your shipped JavaScript has no idea what a User type was.

ts
// You write this
type User = { name: string };
const u: User = { name: "Ada" };
console.log(u);

// The compiler emits this
const u = { name: "Ada" };
console.log(u);
// The 'User' type is gone. Vanished. Compiled away.

Concretely, this means you cannot write if (typeof x === "User"). There is no runtime User. If you need to validate data at runtime (say, an API response), you use a runtime tool like Zod or a hand-written predicate function. Types tell the compiler what should be true. They do not enforce it on data that crosses a network.

The price you pay

  • A build step.You can't just open a file and run it in a browser. You need a compiler (tsc, esbuild, Vite, Next.js, your editor in real-time, etc.). Modern toolchains make this nearly invisible, but it's real.
  • A learning curve. Generics, conditional types, and the occasional cryptic error message are real costs. The first time you see Type 'string' is not assignable to type 'never', you will not feel welcomed.
  • Slightly more typing.Literally. You will write more characters. Modern inference cuts most of the cost, but you'll still annotate function boundaries.
Types are not tests
TypeScript checks the shape of your code. It does not check that your code is correct. function sum(a: number, b: number) { return a - b; } typechecks perfectly. Keep your tests.

When is TS worth it?

  • Yes: any codebase with more than one contributor. Any project that will live longer than a weekend. Any library you publish. Anything with a public API. Front-end apps with non-trivial state.
  • Maybe not:a 10-line script you'll throw away. A quick proof-of-concept where you don't know the shape yet.

In practice, the calculation almost always tips toward yes. Every major framework (React, Vue, Angular, Svelte, Next, Remix) ships first-class TS support. The TS ecosystem is no longer optional in professional front-end work.

Quiz1 / 3

When do TypeScript types exist?

Recap

  • TS is JS plus a compile-time type system. The runtime output is plain JavaScript.
  • It catches typos, wrong shapes, and missing fields before you ship. It powers autocomplete and safe refactors.
  • Types are erased at runtime. To validate untrusted data at the edge (APIs, forms), use a runtime validator.
  • The cost is a build step and a learning curve. For any serious project, the trade is worth it.
  • Types are not tests. They check shapes, not behavior.