0 / 91
Week 5 · Day 31 of 91

TypeScript basic types

TypeScript, Packages, and Tooling

Objective

Annotate domain data and catch obvious mismatches.

TypeScript is similar to design-rule checking: it catches invalid connections before runtime but cannot prove system behavior.

  • primitive types
  • arrays and object types
  • function parameter and return types

Why this matters

On Day 15 you learned that most beginner bugs are not logic errors — they are a value quietly being the wrong type, the text "42" where the number 42 was meant. JavaScript only finds out when the code runs, and often not even then. Today you start writing TypeScript, which finds that class of mistake before the program runs at all. By the end of the hour your inventory model and calculator functions will be typed, and you will have deliberately broken and fixed three type errors so you can recognise them at speed.

What TypeScript is, and what it is not

TypeScript is JavaScript plus type annotations — small notes saying what kind of value each name is allowed to hold. A program called the compiler (tsc) reads those notes, checks that every use is consistent, and reports mismatches. Then the annotations are erased: what runs in the browser is ordinary JavaScript with the types stripped out.

That leads to the two facts that matter most this week, and they must be held together.

What it does: it checks types before the code runs. That is called static checking — static because nothing is executing. It catches mismatched shapes, misspelled property names, wrong argument types, and missing fields.

What it does not do: it cannot prove your program is correct. It has no opinion about whether your total is calculated correctly, whether you meant < or <=, or whether the JSON that arrives at runtime really has the shape you claimed. TypeScript checks consistency with what you declared. If you declare something false, it will happily check your false statement.

TypeScript is design-rule checking

Before a board is fabricated, DRC runs over the layout and reports invalid connections: a trace narrower than the spec, two nets shorted, a footprint whose pad count does not match the part. That is enormously valuable and it is cheap, because it happens before any copper is etched. What DRC will never tell you is whether the circuit does the job — a DRC-clean board can be a perfectly manufacturable amplifier that oscillates. TypeScript is DRC for your code: invalid connections caught before runtime, and no claim at all about behaviour.

Primitive types

A type annotation is a colon and a type name after the variable name.

const componentName: string = "Resistor 10k";
const resistanceOhms: number = 10000;
const inStock: boolean = true;

The three primitives you will use constantly are string, number, and boolean — the same three you met on Day 15, now written down. They are lowercase; String with a capital S is a different thing and almost never what you want.

Most of the time you should not write the annotation. TypeScript performs inference: it works out the type from the value you assigned.

const componentName = "Resistor 10k"; // inferred as string
let stockCount = 42;                  // inferred as number
stockCount = "forty two";             // error
error TS2322: Type 'string' is not assignable to type 'number'.

Read that error as a sentence: you tried to put a string where a number was expected. TS2322 is the error's catalogue number, and searching it finds thousands of explanations. Annotate when inference cannot see your intent — function parameters, empty arrays, outside data — and let inference do the rest.

Arrays and object types

An array of numbers is number[] — the element type followed by square brackets.

const stockLevels: number[] = [42, 7, 0];
const names: string[] = ["Resistor 10k", "Capacitor 100n"];

For the shape of an object, give it a name with a type alias: the keyword type, a name, and a description of each property.

export type Component = {
  id: string;
  name: string;
  category: string;
  stock: number;
  unitPriceCents: number;
};

Type aliases are conventionally capitalised. Now Component[] means "an array of those". If an object is missing a required property, you hear about it immediately:

const capacitor: Component = {
  id: "c-100n",
  name: "Capacitor 100n",
  category: "passive",
  stock: 90,
};
error TS2741: Property 'unitPriceCents' is missing in type
'{ id: string; name: string; category: string; stock: number; }'
but required in type 'Component'.

In plain JavaScript that object is accepted silently, and you discover the missing field three screens later when a price renders as undefined.

The form with required boxes

A paper form with required fields is checked at the counter, before it joins the queue. A form with no required fields is accepted by the counter and rejected two weeks later by someone who needed the missing box. The type alias is the list of required boxes.

Function parameter and return types

Functions are where types pay for themselves, because a function is a contract between two pieces of code. Annotate each parameter, and the return type after the parameter list.

export function totalValueCents(items: Component[]): number {
  let total = 0;
  for (const item of items) {
    total = total + item.stock * item.unitPriceCents;
  }
  return total;
}

export function isLowStock(item: Component, threshold: number): boolean {
  return item.stock < threshold;
}

Two separate protections come from this. Callers are checked:

isLowStock(resistor, "5");
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

And the body is checked against its own promise — a : boolean function that returns a string is an error, so the annotation is not a comment that can drift out of date.

Parameter annotations are effectively required. Leave one off and the compiler objects:

error TS7006: Parameter 'x' implicitly has an 'any' type.

any is the escape hatch: a type meaning "stop checking this value". It is occasionally necessary and almost always a mistake in your own code, because one any silently switches checking off for everything downstream of it. Today's deliverable requires zero uses of it.

Thirty seconds

In any .ts file, write const n: number = 5; then on the next line n.toUpperCase();. Save and run npx tsc --noEmit. TypeScript knows numbers have no toUpperCase — an error you would otherwise have met at runtime, in front of a user.

Walkthrough

Work in the Vite project you scaffolded yesterday.

cd ~/fullstack-journey/inventory-ts

First confirm strict checking is on, because everything above depends on it. Open tsconfig.json and look for "strict": true. Recent TypeScript versions enable strict checking by default, so it may be absent — test rather than assume. Create src/inventory.ts:

export type Component = {
  id: string;
  name: string;
  category: string;
  stock: number;
  unitPriceCents: number;
};

export function totalValueCents(items: Component[]): number {
  let total = 0;
  for (const item of items) {
    total = total + item.stock * item.unitPriceCents;
  }
  return total;
}

Add a temporary line const bad: number = null; and run the type check:

npx tsc --noEmit
src/inventory.ts(13,7): error TS2322: Type 'null' is not assignable to type 'number'.

Real tsc output leads with the file and the (line,column) of the fault, so your numbers will differ from these. If instead it reports nothing, strict checking is off — add "strict": true inside compilerOptions in tsconfig.json and run again. Delete the temporary line. Now add a value and a caller that are both wrong on purpose:

const resistor: Component = {
  id: "r-10k",
  name: "Resistor 10k",
  category: "passive",
  stock: "42",
  unitPriceCents: 3,
};

console.log(totalValueCents(resistor));
src/inventory.ts(17,3): error TS2322: Type 'string' is not assignable to type 'number'.
src/inventory.ts(21,29): error TS2345: Argument of type 'Component' is not assignable to parameter of type 'Component[]'.
  Type 'Component' is missing the following properties from type 'Component[]': length, pop, push, concat, and 35 more.

Two real bugs, neither of which would have appeared until the code ran. Fix them — stock: 42, and pass [resistor] — and confirm npx tsc --noEmit prints nothing at all. Silence is success, the convention you first met on Day 2.

Checkpoint

Explain the second error in plain JavaScript terms: you handed the function one object where it expected a list of objects, so the loop would have iterated over nothing.

How to use AI today

Today's mode is tutor. The best tutor-style request asks the AI to explain the concept, give a small example, and then let you attempt it — never to hand you a corrected file. With type errors there is a specific version of that request worth memorising.

Tutor mode, on your first real error

"Explain each TypeScript error in plain JavaScript terms before showing a correction." Read the explanation, close it, and write the fix yourself. If you paste in a fix you cannot narrate, you have swapped a five-minute lesson for a permanent gap.

Your turn

  1. In src/inventory.ts, define the Component type alias with at least the five properties above. Add id as a string, not a number — you will thank yourself in Week 7.
  2. Write totalValueCents(items: Component[]): number and isLowStock(item: Component, threshold: number): boolean, ported from your Week 4 calculator logic.
  3. Add a third annotated function of your own, such as formatPrice(cents: number): string.
  4. Create a Component[] array of three real components and call all three functions from src/main.ts. Run npm run dev and confirm the values print in the browser console.
  5. Now break it three times, one at a time, running npx tsc --noEmit after each and writing the full error text into notes/day-31.md:
    • put a string in a number property (expect TS2322),
    • remove a required property from one component (expect TS2741),
    • pass an argument of the wrong type to one of your functions (expect TS2345).
  6. Fix all three. Confirm npx tsc --noEmit prints nothing, then run npm run build and confirm it completes.
  7. Search your files for the word any. There should be none. Commit.

You are done when

npx tsc --noEmit is silent, npm run build succeeds, and notes/day-31.md holds three real error messages with a one-line plain-English translation of each.

Common pitfalls

  • Reaching for any to make an error go away. The error was information. any deletes the information and keeps the bug.
  • Believing a clean type check means the code works. It means the shapes agree. Your maths can still be wrong, and you still have to run it.
  • Renaming .js to .ts and panicking at fifty errors. That is normal and it is a to-do list. Convert one file at a time and start with the data model.
  • error TS6133: 'x' is declared but its value is never read. Not a type mismatch — the project is configured to flag unused variables. Delete it or use it.

Verify it yourself

Open today's reference, the TypeScript Handbook, and read The Basics and Everyday Types.

  1. The Handbook states what happens to type annotations when the code is compiled. Copy that sentence into your notes. Does it match this lesson's claim that types are erased?
  2. Everyday Types shows a second syntax for array types besides number[]. Find it and note it.
  3. Find the Handbook's own warning about any, and write down its reason in your words.

Confirming a lesson from the official docs is the point of this section — do it before you close the tab.

The hour

  1. 0–5 min Recall

    Without notes, state yesterday’s main idea and one unresolved question.

  2. 5–20 min Learn

    Read only the listed concept notes and official reference sections needed today.

  3. 20–48 min Build

    Type the component inventory model and calculator functions. Deliberately create and fix three type errors.

  4. 48–55 min Explain and verify

    Run the result, inspect evidence, and explain the data/control flow in your own words.

  5. 55–60 min Quiz and commit

    Complete the quiz, record one lesson, and commit the verified change when applicable.

What to hand in

Deliverable

Typed models with no use of any.

Working with AI today

AI as tutor

Ask for explanations, analogies, questions, and hints. Do not request a complete finished solution first.

Explain each TypeScript error in plain JavaScript terms before showing a correction.

References

End-of-day quiz

Q1 What is TypeScript primarily doing?
Q2 Which result best proves today’s work is complete?
Q3 What is the best tutor-style AI request?

Explain-back gate

Pass the quiz above to unlock completion.

Quiz + explain-back checks required.