Type Aliases vs Interfaces

intermediate
10 min

Type Aliases vs Interfaces

TypeScript gives you two ways to name a type: type aliases and interface declarations. For plain object shapes they are nearly interchangeable, which is exactly why the question "which should I use?" comes up on every team. This lesson lays out what each can do, the real differences, and a practical decision rule.

What They Share

Both can describe an object shape, be extended, be implemented by classes, and be generic:

typescript
interface PointI { x: number; y: number } type PointT = { x: number; y: number }; // Both extend: interface Point3I extends PointI { z: number } type Point3T = PointT & { z: number }; // Both work with classes: class Vec implements PointI { x = 0; y = 0 } class Vec2 implements PointT { x = 0; y = 0 }

Because TypeScript is structural, PointI and PointT are fully assignable to each other. For a simple object shape, the choice is stylistic.

What Only Type Aliases Can Do

A type alias can name any type, not just object shapes:

typescript
type Id = string | number; // union type Pair = [number, number]; // tuple type Handler = (event: string) => void; // function type Keys = keyof PointI; // operator result type Maybe<T> = T | null | undefined; // generic union type Getters<T> = { // mapped type [K in keyof T as `get${string & K}`]: () => T[K]; };

Unions, tuples, mapped types, conditional types, and template literal types can only be named with type. If your type is not an object shape, the decision is already made.

What Only Interfaces Can Do

Declaration merging. Multiple interface declarations with the same name merge into one:

typescript
interface Window { myAppVersion: string } // merges with the built-in Window type — // window.myAppVersion is now typed everywhere

This is essential for augmenting global types and third-party libraries (declare module augmentation). A type alias with a duplicate name is simply an error.

Interfaces are also slightly friendlier in tooling: error messages and editor hovers show the interface name, while aliases are sometimes expanded into their full structure, which can be noisy for large types. In very large codebases interfaces can be marginally cheaper for the compiler when extended repeatedly, though for most projects the difference is unmeasurable.

extends vs Intersection: A Subtle Difference

interface extends and & usually produce the same result, but they handle conflicts differently. Extending with an incompatible property is an error at the declaration site — good, loud, early:

typescript
interface A { prop: string } interface B extends A { prop: number } // Error: types of prop are incompatible

An intersection silently produces prop: string & number, which collapses to never — the error surfaces later, somewhere confusing, when you try to create a value. This is a genuine argument for extends when building object hierarchies.

A Practical Decision Rule

  • Use interface for object shapes that others may extend or implement — public API surfaces, props, entity models — and always when you need declaration merging.
  • Use type for unions, tuples, function types, mapped/conditional types, and quick local compositions.
  • Above all: be consistent within a codebase. Many teams simply standardize on one default (either is defensible) and use the other where it is required.

The official TypeScript documentation suggests using interface until you need features from type — a perfectly good default.

Key Takeaways

  • For plain object shapes, aliases and interfaces are interchangeable — structural typing sees no difference.
  • Only type can name unions, tuples, functions, and mapped/conditional types.
  • Only interface supports declaration merging, which module augmentation depends on.
  • extends surfaces property conflicts immediately; & can silently create never.
  • Pick a team convention and apply it consistently.

Next lesson: tsconfig.json and Compiler Options — configuring TypeScript for real projects.

Type Aliases vs Interfaces - TypeScript | CodeYourCraft | CodeYourCraft