Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

When to use Type Aliases or Interfaces in TypeScript

August 04, 2020
typescript

Type aliases and interfaces in TypeScript have similar capabilities. In this post, we discuss which approach is best for different use cases.

Type Aliases v Interfaces

Representing primitive types

Type aliases can represent primitive types, but interfaces can’t.

type Name = string;

Winner: Type alias

It is worth noting that it is generally simpler to use the primitive type directly rather than aliasing it.

Representing arrays

Type aliases and interfaces can both represent arrays.

Let’s compare the syntax for both approaches:

type Names = string[];

interface Names {
  [index: number]: string;
}

The type alias approach is a lot more concise and clearer.

Winner: Type alias

It is worth noting that it is often simpler to use the array type directly rather than aliasing it.

Representing tuples

Winner: Type aliases can represent tuple types, but interfaces can’t:

type Point = [number, number];

Winner: Type alias

Representing functions

Type aliases and interfaces can both represent functions.

Let’s compare the syntax for both approaches:

type Log = (message: string) => void;

interface Log {
  (message: string): void;
}

The type alias approach is a lot more concise and clearer.

Winner: Type alias

Creating union types

Type aliases can represent union types but interfaces can’t:

type Status = "pending" | "working" | "complete";

Winner: Type alias

Representing objects

Type aliases have wiped the floor with interfaces so far. However, the strength of interfaces is representing objects.

Let’s compare the syntax of both approaches:

type Person = {
  name: string;
  score: number;
};

interface Person {
  name: string;
  score: number;
}

The type alias approach is again a little more concise, but the equals operator (=) can result in the statement being confused for a variable assignment to an object literal.

Winner: Tie

Composing objects

Type aliases and interfaces can both compose objects together.

Let’s compare the syntax of both approaches:

type Name = {
  firstName: string;
  lastName: string;
};
type PhoneNumber = {
  landline: string;
  mobile: string;
};
type Contact = Name & PhoneNumber;

interface Name {
  firstName: string;
  lastName: string;
}
interface PhoneNumber {
  landline: string;
  mobile: string;
}
interface Contact extends Name, PhoneNumber {}

The type alias approach is more concise.

Type aliases can compose interfaces and visa versa:

type Name = {
  firstName: string;
  lastName: string;
};
interface PhoneNumber {
  landline: string;
  mobile: string;
}
type Contact = Name & PhoneNumber;

Only type aliases can compose union types though:

type StringActions =
  | { type: "loading" }
  | { type: "loaded"; data: string[] };
type NumberActions =
  | { type: "loading" }
  | { type: "loaded"; data: number[] };
type Actions = StringActions & NumberActions;

Winner: Type alias

Authoring a library

One important feature that interfaces have that type aliases don’t is declaration merging:

interface ButtonProps {
  text: string;
  onClick: () => void;
}
interface ButtonProps {
  id: string;
}

This is is useful for adding missing type information on 3rd party libraries. If you are authoring a library and want to allow this capability, then interfaces are the only way to go.

Winner: Interfaces

Summary

Type aliases generally have more capability and a more concise syntax than interfaces. However, interfaces have a nice syntax for objects, and you might be used to this concept from other languages.

The important thing is to be consistent in whichever approach is used so that the code isn’t confusing.

Did you find this post useful?

Let me know by sharing it on Twitter.
Click here to share this post on Twitter

If you to learn more about TypeScript, you may find my TypeScript course useful:

Learn TypeScript

Find out more