Course outline · 0% complete

0/26 lessons0%

Course overview →

Typed Objects

lesson 2-2 · ~11 min · 5/26

Describing an object's shape

Almost everything a real program passes around is an object: a user record, a product, a config. That makes object shapes the place where typos and missing fields do the most damage, and the place where the type system pays off most.

Objects get a type that lists each property and its type:

const user: { name: string; age: number } = {
  name: "Ada",
  age: 36,
};

The part in braces after the colon is the object type: property names with their types. TypeScript now enforces the shape in both directions.

What you writeWhat happens
A missing propertyProperty 'age' is missing at compile time
An extra propertyError, the shape says exactly name and age
A typo such as user.nmaeError, with a helpful Did you mean 'name'?

That last row matters most. In JavaScript, user.nmae silently gives undefined and the crash happens somewhere else entirely. You debugged exactly that class of bug in Advanced JavaScript.

Enforcing an object shape

const user: { name: string; age: number } = {
  name: "Ada",
  age: 36,
};

console.log(user.name + " is " + user.age);
console.log("next year: " + (user.age + 1));

Output

Ada is 36
next year: 37

Because age is typed as a number, arithmetic like user.age + 1 is checked and safe. The parentheses around it matter for a JavaScript reason rather than a type reason: without them, the leading string would turn the whole expression into concatenation and print next year: 361.

Now mistype the first access as user.nmae. The compiler rejects it and usually suggests the correct spelling. In plain JavaScript that same typo evaluates to undefined, the line prints undefined is 36, and nothing breaks loudly until some later code tries to use the value.

An array of typed objects

Objects rarely travel alone. An array of typed objects is the most common data shape in real code, and the annotation composes exactly as you would guess. { name: string; hours: number }[] reads as "array of objects with this shape".

const team: { name: string; hours: number }[] = [
  { name: "Ada", hours: 6 },
  { name: "Grace", hours: 4 },
];

let total = 0;
for (const member of team) {
  console.log(member.name + " logged " + member.hours + "h");
  total += member.hours;
}
console.log("team total: " + total + "h");

Output

Ada logged 6h
Grace logged 4h
team total: 10h

How the annotation composes

  • The [] applies to the whole braced shape, so every element must match it. Adding { name: "Alan" } to the array is rejected because hours is missing, which is precisely the check you want when building data by hand.
  • Inside the loop, member is known to have exactly name and hours, so both property accesses are checked and both autocomplete.
  • This annotation is getting long, and repeating it across several functions would be tedious. Naming the shape once is the subject of the next lesson.

Writing to a property the shape does not declare

Given const p: { x: number; y: number }, the line p.z = 5 is a compile error: property z does not exist on the declared type.

The declared shape has exactly x and y, and TypeScript treats that shape as the contract. Reading or writing any property outside it is an error, not a silent extension of the object.

This is a deliberate departure from plain JavaScript, where objects grow new properties on demand. That flexibility is genuinely useful in small scripts and genuinely dangerous in large ones, because a misspelled assignment creates a brand-new property instead of updating the one you meant, and nothing reports it.

A three-property book object

Here is one object annotated with three properties of three different types, followed by two lines of output built from it.

const book: { title: string; pages: number; inPrint: boolean } = {
  title: "Dune",
  pages: 412,
  inPrint: true,
};

console.log(book.title + " has " + book.pages + " pages");
console.log("in print: " + book.inPrint);

Output

Dune has 412 pages
in print: true

Two punctuation rules that differ

  • Inside an object type, properties are separated by semicolons, as in { title: string; pages: number; inPrint: boolean }. Commas are also accepted, and semicolons are the more common house style.
  • The object literal below uses commas, exactly like the JavaScript you already write.
  • Mixing the two up is a beginner stumble worth naming once. The type describes what a value must look like, the literal is an actual value, and they are two separate pieces of syntax that happen to sit close together on the page.