Skip to content
Lesson 14 of 15

Step 1 of 7 · Reading · ~3 min

Learn

Type System Essentials

Type Aliases vs Interfaces

Both type and interface give a name to a shape, and for ordinary objects they are interchangeable. By the end of this lesson you will know the few places where only one of them works, and you will use both together to model a recursive structure.

Interface

interface Product {
    name: string;
    price: number;
    describe(): string;
}

interface Perishable extends Product {   // inheritance with extends
    days: number;
}

const milk: Perishable = {
    name: 'Milk', price: 1.2, days: 7,
    describe() { return `${this.name} lasts ${this.days} days`; },   // `this` is the object the method is called on
};

A class can promise to follow an interface: class Crate implements Product { ... } must then supply every member.

Type alias

type Product = {
    name: string;
    price: number;
};

Looks the same, but a type alias can name things an interface cannot:

type Id = string | number;                     // union
type Point = [number, number];                 // tuple
type Callback = (code: number) => void;        // function type
type Meters = number;                          // plain alias
type Cart = Product[];                         // array of something
type Tagged = Product & { tag: string };       // intersection

Composition with & has a similar effect to extends:

type Perishable = Product & { days: number };

The differences that matter

Interfaces are open: declaration merging. Two interfaces with the same name in the same scope become one:

interface Settings { theme: string; }
interface Settings { fontSize: number; }    // merged: Settings has both fields

That is how libraries let you add fields to types you do not own, such as Window or Express's Request. A repeated type Settings = ... is an error: duplicate identifier.

Types are closed but more flexible. Only type can be a union, tuple, primitive alias, or the result of a conditional or mapped type. interface Id = string | number does not parse.

Extending a conflict. interface B extends A is an error if B redeclares a field of A with an incompatible type. An intersection A & B does not complain; the conflicting field silently becomes never.

Recursion works with both. A thread of replies refers to itself:

type Reply = { text: string; replies: Reply[] };

The two can reference each other freely, which is how a union of interfaces is built:

interface Success { ok: true; value: number }
interface Failure { ok: false; error: string }
type Outcome = Success | Failure;            // the union itself must be a type alias

Which to use

Use interface for object shapes that other code may extend, class contracts (implements), and declarations you want to be mergeable. Use type for unions, intersections, tuples, function types, mapped and conditional types, and plain aliases. For everyday objects either works: pick one convention and keep it consistent. For the type checker's performance on very large codebases, interfaces that extend each other are slightly cheaper than long intersections.

Common mistakes

  • Trying to merge two type aliases. Duplicate identifier; use an interface.
  • Writing interface X = A | B. Unions need type.
  • Prefixing interfaces with I. IUser is a C# habit and is discouraged in modern TypeScript.
  • Assuming extends and & behave the same on conflicts. One errors, the other gives you never.
  • Switching styles file by file. Mixed conventions make code harder to read.

Your exercise

Model a small file system. A file has a size; a directory holds a list of entries, each of which is a file or a directory. That is a union of two object shapes that refer back to the union, so it uses both an interface and a type alias. The starter parses a JSON tree; you declare the types and write the function that walks it. Because a directory contains entries that may themselves be directories, that function calls itself on each child. Remember that a directory with no children still counts as one level of depth.

Up nextEnums and Literal TypesType System Essentials

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…