Why Types (and Why Now)
Advanced · 16 min read · ▶ live playground · ✦ checkpoint
The bigger a JavaScript program gets, the more bugs come from simple broken promises: "this is a number", "this property exists", "this function returns the shape we agreed on." TypeScript is JavaScript with a type-checking layer added on top, so your editor and build can catch many of those broken promises before users do.
A type system is a set of rules for describing which values are allowed and which operations are safe. TypeScript does not replace JavaScript, and it does not make the browser run a new language. You still write JavaScript ideas: functions, objects, arrays, modules, promises. TypeScript checks the program first, then the type layer is erased and ordinary JavaScript runs.
What types delete
Types are not about making code look fancy. They delete whole classes of boring bugs.
Start with a plain checkout shape:
type CartItem = {
id: string;
title: string;
priceCents: number;
inStock: boolean;
};
function totalCents(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.priceCents, 0);
}
const cart: CartItem[] = [
{ id: "notebook", title: "Notebook", priceCents: 299, inStock: true },
{ id: "pen", title: "Pen", priceCents: 149, inStock: true },
];
const total = totalCents(cart);
console.log(total);Nothing here is exotic. CartItem says every item needs an id, title, priceCents, and inStock. totalCents says it accepts an array of those items and returns a number.
That lets TypeScript stop mistakes like these:
Property 'priceCent' does not exist on type 'CartItem'. Did you mean 'priceCents'?
Type 'string' is not assignable to type 'number'.
Property 'inStock' is missing in type '{ id: string; title: string; priceCents: number; }'
but required in type 'CartItem'.Those are three different bug classes:
- Wrong name:
priceCentinstead ofpriceCents. - Wrong kind of value:
"299"where the program expects299. - Wrong object shape: an item missing a required property.
JavaScript would happily start the program and let those problems travel until some later line produces NaN, undefined, a broken UI, or a crash. TypeScript catches them at the edge where the promise is broken.
Types make invalid states harder to write
Types also shrink the number of possible states your program can be in. If a save button can be idle, saving, saved, or failed, do not leave that as "any string someone happened to type."
type SaveState = "idle" | "saving" | "saved" | "failed";
function buttonText(state: SaveState): string {
switch (state) {
case "idle":
return "Save";
case "saving":
return "Saving...";
case "saved":
return "Saved";
case "failed":
return "Try again";
}
}
const currentState: SaveState = "saving";
const label = buttonText(currentState);
console.log(label);You will learn the syntax for literal types and unions in the next lesson. For now, notice the design move: SaveState is not "some text". It is one of four exact values. A typo like "succes" is not a possible state anymore.
This is where types start to feel less like paperwork and more like design. Instead of writing comments that say "please only pass one of these values", you make the rule part of the code the editor can enforce.
What types cannot delete
TypeScript is a checker, not a mind reader. It cannot know whether your discount policy is generous enough, whether your copy is clear, or whether your product rule is fair. It also cannot automatically trust data that arrives from outside your program.
If an API sends this at runtime, TypeScript cannot stop the network from lying:
{ "id": "pen", "priceCents": "free" }Your code still needs validation at runtime for user input, network responses, files, database rows, and anything else that crosses a boundary. The rule is simple: types protect the code you control; runtime checks protect data you receive.
Types as documentation and autocomplete fuel
Comments can rot because nothing checks them. Types stay closer to the truth because the checker uses them every time the project is checked.
type Invoice = {
id: string;
customerEmail: string;
totalCents: number;
paidAt: Date | null;
};
function invoiceSummary(invoice: Invoice): string {
const status = invoice.paidAt === null ? "unpaid" : "paid";
return `${invoice.id}: ${invoice.customerEmail} owes ${invoice.totalCents} cents (${status})`;
}Before reading the function body, you already know a lot:
invoice.idandinvoice.customerEmailare strings.invoice.totalCentsis a number, so math is allowed.invoice.paidAtmay be aDateornull, so code has to handle both.invoiceSummaryreturns a string.
That is documentation, but it is also tool fuel. When you type invoice., the editor can offer id, customerEmail, totalCents, and paidAt. When you rename customerEmail, the editor can update real references instead of doing a risky search-and-replace. When you accidentally return a number from invoiceSummary, the checker can point at the function contract.
This is the difference between "I hope I remembered the shape" and "the project keeps the shape in one inspectable place."
Why now
For a long time, JavaScript courses could treat TypeScript as optional trivia. That is not the professional reality anymore. Modern JavaScript teams often still say "our JavaScript app", but the files are commonly .ts and .tsx, the editor feedback is powered by TypeScript, and the build fails if the types do not line up.
src/
checkout.ts
invoices.ts
App.tsx
api/
receipts.tsThis course is still a JavaScript course because JavaScript is the runtime language. TypeScript scales that runtime language for teams, larger codebases, editor tooling, and refactors. You do not need to become a type theorist to benefit from it. You need to know what promises types make, where those promises end, and how to read the feedback.
Section 20 is a four-lesson taster, using static TypeScript examples so we stay focused on concepts. For full hands-on TypeScript practice, use the full TypeScript course; that is the live-practice home for the checker, compiler workflow, and larger typed projects.
Next, you will learn the essential syntax: annotations, inference, object and array types, unions, literal types, interface versus type, optional and readonly properties, and the narrowing rules that make TypeScript feel smart.
Checkpoint
Answer all three to mark this lesson complete