Object types and interfaces

TypeScript · Essentials · 12 min

Almost all real data is objects; interfaces are how a codebase names and shares their shapes.

An object type lists properties and their types: { id: number; name: string }. Separators can be ; or ,. When a shape is used in more than one place, give it a name with an interface:

interface User {
  id: number;
  name: string;
  email?: string;              // optional
  greet(other: User): string;  // method
}

Any object with at least those properties satisfies User — no implements or class needed, because typing is structural. Extra properties are fine when you pass an existing variable.

There is one exception you will hit quickly: an object literal written directly where a type is expected gets an excess property check. const u: User = { id: 1, name: "A", emial: "x" } is an error, because a property the type doesn't know about is most likely a typo.

Interfaces can extend others, combining shapes:

interface Admin extends User { permissions: string[] }

Accessing a property that isn't declared is an error, which catches typos. When an object is used as a dictionary with arbitrary keys, use an index signature — { [key: string]: number } — or the Record<string, number> utility type.

Optional properties are typed T | undefined when you read them, so you must check before using: user.email?.toLowerCase().

Interfaces and object types also describe functions' parameters and return values, nested objects, and arrays of objects, so you will write them constantly. Name the shapes that cross module boundaries; inline the one-off ones.

Example

interface Address {
  city: string;
  zip?: string;                  // optional
}

interface User {
  id: number;
  name: string;
  address: Address;
  greet(other: User): string;
}

interface Admin extends User {
  permissions: string[];
}

const ada: Admin = {
  id: 1, name: "Ada", address: { city: "London" }, permissions: ["all"],
  greet(other) { return `Hi ${other.name}, I'm ${this.name}`; },
};

console.log(ada.address.zip?.trim() ?? "no zip", ada.greet(ada));
// @ts-expect-error -- Object literal may only specify known properties
const typo: Address = { city: "Paris", zpi: "75001" };

Remember

  • Interfaces name object shapes; any object with those members fits
  • prop?: T marks optional properties (read as T | undefined)
  • Object literals get excess property checks that catch typos
  • extends builds bigger interfaces from smaller ones

Watch out for

  • Assuming excess property checks always apply — they only apply to fresh object literals.

Check yourself

  1. const p = { x: 1, y: 2, label: "a" }; const q: { x: number; y: number } = p; Is this an error?
  2. How do you declare that a User may or may not have a phone property?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.typescriptlang.org/docs/handbook/2/objects.html