Settings
Your save file

Progress lives in this browser, on this device. Download the save file to move it to another device, or to keep a copy in case this browser clears its storage.

Season 2
Week 2 of 12

Reading time · 3 min

One comp · scored

Up next

Week 3 · Nominations

Locked until you win

Week 2 · Early Weeks

Getting To Know The House

Interfaces and type aliases

Describing object shapes: optional, readonly, and the one time interface vs type matters.

Every codebase has that one object. You built it eight months ago, it flows through eleven functions, and the only documentation for its shape is vibes and a console.log you deleted in 2024. Last week you taught TypeScript to check the values you hand a function. This week you teach it to describe the objects those values live inside, so neither of you has to remember the shape from memory again.

Describing a shape instead of guessing at one

In plain JS, an object's shape lives in your head, or in whatever function happened to build it last. TypeScript gives that shape a name with an interface: a list of properties, each with its own type, that any object claiming to be that shape has to match.

The ES6 you write

const player = {
  name: 'Cliff',
  twitterHandle: '@cliffhogg',
  seasonNumber: 21,
}

The TS version

interface Player {
  name: string
  twitterHandle?: string
  readonly seasonNumber: number
}
 
const player: Player = {
  name: 'Cliff',
  seasonNumber: 21,
}

What changed

The JS object on the left has a shape, you just cannot ask anything to check it. The TS version names that shape with interface Player, and the const player: Player line tells the compiler which shape this particular object is supposed to satisfy. Try to typo seasonNumber as season and TypeScript catches it before you save.

Notice player above skips twitterHandle entirely and still compiles. That is the next piece.

Optional properties: the ?

A ? right after a property name means "this property is allowed to be missing." Not null, not empty string, just plain absent from the object. If you have written PHP 7 nullable type hints like ?string $handle = null, your instinct is close but not identical: PHP's ? says the value can be null, TypeScript's ? on an interface property says the key itself can be left out of the object altogether. A player without a twitterHandle property is valid. A player with twitterHandle: null is a different claim, and null is not what the ? promises here.

readonly: what it does, and what it does not

readonly on a property means the compiler will stop you from writing to it after the object is created. player.seasonNumber = 22 is a compile error, full stop, right there in your editor. What it will not do is freeze the object at runtime. Compile the code above and ship it, and player.seasonNumber = 22 runs just fine in plain JavaScript, because readonly is erased along with every other type, exactly like last week. If you need an actual runtime-enforced freeze, that is what Object.freeze is for, a completely different tool solving a completely different problem. readonly protects you at the keyboard, not in production.

That is the whole lesson. Now prove it in the comp below.

Up next

Week 3 · Nominations

Union and literal types

Locked until you win