1interface User {2 name: string;3 age: number;4 email?: string;5}6const ana: User = { name: "Ana", age: 30 };const ana: User = { name: "Ana" };const ana: User = { name: "Ana", age: "30" };7ana.age = 31;ana.agee = 31;8console.log(ana.name, ana.age);namestringagenumberemail?string✓✕✓✕✓✕✕ no slot: agee$ node user.jsAna 31name"Ana"age30name: "Ana"age: 30age: "30".agee31{ "Ana", 31 }
Back: user.ts and interface User, the shape (a slot per property, with its type)Front: the object ana (a box per property, with its value) and the Node.js outputTokens: properties hopping into their slots; a tick means it fits, a cross means tsc reports an errorAt the back: user.ts, and interface User drawn as a tray of typed slots. In front of the slots stands the object ana, one box per property; at the front left, the output of Node.js. tsc checks ana against User before anything runs: a missing property, a value of the wrong type and a misspelt name are all caught. At run time the interface is gone and the program prints Ana 31. By default tsc still writes the .js file even when it finds type errors (turn on noEmitOnError to stop that). Either way, you see the error first.

Objects

  1. An object keeps related values together under names. { name: "Ana", age: 30 } is one object with two properties: name holds the text "Ana" and age holds the number 30. const ana gives it a name.

Shapes

The check

Running it

What happens

;; step 1/9 · object
line 6 of user.ts
  const ana: User = { name: "Ana", age: 30 };

one object, two properties:
  name  →  "Ana"   a string (text)
  age   →  30      a number
read one with a dot:  ana.name  is  "Ana"

TypeScript compares shapes, not names: any object with a string name and a number age fits User, even if it was never called a User. This is called structural typing. The user.js shown is exactly what tsc 5.9 writes with no settings. Its default target is ES5, an older JavaScript, so const is written as var; set target to ES2015 or later to keep const.