SyntaxStudy
Sign Up
TypeScript Beginner 1 min read

Type Aliases vs Interfaces

A type alias creates a new name for any type — not just object shapes, but also primitives, unions, intersections, tuples, and mapped types. The syntax uses the type keyword followed by an assignment. Unlike interfaces, type aliases can represent any type expression, making them more flexible in certain scenarios. The most important practical difference between type aliases and interfaces is that interfaces are open — they can be extended via declaration merging — while type aliases are closed. If you need to allow augmentation (common when writing library types), interfaces are the right choice. For everything else, including union types, mapped types, and conditional types, you must use type aliases because interfaces cannot express them. Both can be used to define object shapes, and in those cases the choice is largely stylistic. The TypeScript team's recommendation is to use interfaces for public API contracts and type aliases for internal types, complex type constructions, and unions. In practice, many teams pick one and stick with it for consistency, reserving the other for cases where only it will work.
Example
// Type alias for an object shape
type Point = {
    x: number;
    y: number;
};

// Type alias for a union — interfaces cannot do this
type Result<T> =
    | { success: true; data: T }
    | { success: false; error: string };

function divide(a: number, b: number): Result<number> {
    if (b === 0) return { success: false, error: "Division by zero" };
    return { success: true, data: a / b };
}

const r = divide(10, 2);
if (r.success) console.log(r.data); // 5

// Type alias for a primitive (useful for documentation)
type UserID = number;
type Email  = string;

// Type alias for a tuple
type Pair<A, B> = [A, B];
const entry: Pair<string, number> = ["score", 98];

// Interface extension vs type intersection
interface Base { id: number }
interface Extended extends Base { name: string } // interface

type BaseType     = { id: number };
type ExtendedType = BaseType & { name: string };  // type alias

// Both work the same for object shapes
const a: Extended     = { id: 1, name: "A" };
const b: ExtendedType = { id: 2, name: "B" };

// Only type aliases can express mapped types
type Optional<T> = { [K in keyof T]?: T[K] };
type PartialPoint = Optional<Point>; // { x?: number; y?: number }