TypeScript Interfaces

A quick reference for defining object contracts, optional fields, index signatures, and interface inheritance.

TL;DR

  1. Define object contracts using the interface keyword and typed members.
  2. Mark non-mandatory fields optional using the ? modifier.
  3. Compose multiple structural contracts together with the extends keyword.

Interface Syntax

    interface declaration

    Defines the required shape and types of an object.

    interface User {
      id: number;
      username: string;
    }
    optional property

    Permits omission of a property using a question mark.

    interface Profile {
      displayName: string;
      bio?: string;
    }
    readonly modifier

    Prevents modifying property values after object creation.

    interface Point {
      readonly x: number;
      readonly y: number;
    }
    typed object literal

    Annotates an object to enforce contract adherence.

    const member: User = {
      id: 101,
      username: 'pat_dev'
    };

Methods and Signatures

    method signature

    Specifies function names, parameters, and return shapes.

    interface Calculator {
      add(a: number, b: number): number;
      clear(): void;
    }
    function type interface

    Describes callable function contracts using call signatures.

    interface Formatter {
      (input: string, uppercase?: boolean): string;
    }
    const format: Formatter = (s) => s.trim();
    construct signature

    Describes newable constructor signatures for factory patterns.

    interface ClockConstructor {
      new (hour: number, minute: number): ClockInterface;
    }
    interface ClockInterface {
      tick(): void;
    }

Extending Interfaces

    extends keyword

    Inherits properties from a base interface into a child.

    interface Vehicle {
      wheels: number;
    }
    interface Car extends Vehicle {
      make: string;
    }
    multiple inheritance

    Combines properties from multiple interfaces separated by commas.

    interface Named { name: string; }
    interface Aged { age: number; }
    interface Person extends Named, Aged {
      id: string;
    }
    property narrowing

    Refines an inherited property to a more specific subtype.

    interface Event {
      type: string;
    }
    interface ClickEvent extends Event {
      type: 'click';
      x: number;
    }

Index Signatures

    string index signature

    Allows arbitrary string keys mapped to a consistent type.

    interface StringDictionary {
      [key: string]: string;
    }
    const headers: StringDictionary = {
      'Content-Type': 'application/json'
    };
    numeric index signature

    Describes array-like structures accessed by numeric indexes.

    interface StringArray {
      [index: number]: string;
      length: number;
    }
    const list: StringArray = ['a', 'b'];
    readonly index

    Locks dictionary keys from runtime reassignment.

    interface ReadonlyConfig {
      readonly [key: string]: boolean;
    }
    const flags: ReadonlyConfig = { debug: true };

Declaration Merging

    interface merging

    Combines two declarations with the same name into one.

    interface Box {
      height: number;
    }
    interface Box {
      width: number;
    }
    const box: Box = { height: 10, width: 20 };
    global augmentation

    Extends global browser or runtime types cleanly.

    interface Window {
      analyticsTracker?: {
        track(event: string): void;
      };
    }
    class interface merge

    Merges an interface with a class to declare extra properties.

    class Album {}
    interface Album {
      artist: string;
    }
    const a = new Album();
    a.artist = 'Daft Punk';

Tips

  1. Prefer interface over type for defining public library API boundaries and contracts that external consumers might need to extend.
  2. Combine readonly and optional property modifiers to create robust configuration interfaces that resist accidental runtime mutations.

Warnings

  1. Be cautious when reusing interface identifiers because TypeScript automatically applies declaration merging across files in identical scopes.
  2. Remember that assigning fresh object literals enforces excess property checks that do not trigger when passing intermediate const references.

In Practice

FAQ