Explain

What is the difference between these statements (interface vs type) in TypeScript?

In TypeScript, both type and interface can describe object shapes (i.e., what properties an object has), and for many basic use cases, they act very similarly. However, there are a few differences in capabilities, syntax, and how the compiler treats them. Below is a concise breakdown:

1. Basic Examples

interface

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

Recommended Courses

type

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

In these simple examples, both define an object shape and can be used interchangeably for most purposes (e.g., function parameters, variable annotations, etc.). They both define the shape Person { name: string; age: number }.

2. Key Differences

  1. Declaration Merging (Extending/Reopening)

    • Interfaces support declaration merging, meaning you can define the same interface in multiple places and TypeScript will merge them.
      interface Person {
        name: string;
      }
      
      interface Person {
        age: number;
      }
      
      // Merged: { name: string; age: number }
      const p: Person = { name: 'Alice', age: 30 };
      
    • Type aliases do not support declaration merging. If you try to write the same type name in multiple places, you’ll get a redefinition error.
  2. Extending vs. Intersection

    • Interfaces use the extends keyword to inherit from other interfaces.
      interface Animal {
        name: string;
      }
      
      interface Bear extends Animal {
        honey: boolean;
      }
      
    • Type aliases can use intersections (&) to combine object types:
      type Animal = {
        name: string;
      };
      
      type Bear = Animal & {
        honey: boolean;
      };
      
    • Result wise, they can achieve a similar effect, but the syntax is different.
  3. Union and Other Advanced Types

    • Type aliases can represent unions, primitives, or more advanced constructs:
      type StringOrNumber = string | number;
      type Coordinates = [number, number];
      type Callback = (x: number) => string;
      
    • Interfaces cannot represent these things directly (e.g., you cannot create an interface that is “string or number”).
  4. Name Conflicts & Error Messages

    • Error and IntelliSense messages can be more straightforward with interfaces because they show up by name in many places.
    • Type aliases sometimes produce more expanded or less direct error messages (especially for large or deeply nested types).
  5. Recommended for Library Declarations

    • Many prefer interfaces for public library .d.ts because they can be reopened (declaration merging) by other consumers, e.g., adding new properties to an existing interface in a third-party library.
    • Type aliases can be more flexible for complex or composite scenarios in application code.

3. Which One to Use?

  • Use interface when:

    • You want to describe the shape of objects in a straightforward manner (especially in public APIs).
    • You expect consumers might need to merge declarations (for adding properties in a library).
    • You want extendable or re-openable definitions.
  • Use type when:

    • You need advanced type features (unions, mapped types, etc.).
    • You prefer to define function signatures, tuple types, or union types more succinctly.
    • You want to intersect multiple object types (type Combined = A & B & {...}).

In many cases, either can represent an object shape. Team or style guide preferences often matter more than a purely technical reason. But the key distinctions (declaration merging, advanced types, union usage) are typically the deciding factors.

Recommended Resource

Bottom Line

  • Interfaces are extendable, can be reopened, and are great for object shapes in library/public API definitions.
  • Type aliases are more flexible for advanced type constructs (unions, tuples, primitives, etc.) and may produce slightly different compiler output and error messages.

Either way, both provide strong type-checking for your TypeScript code—choose the one that best fits your extensibility or type complexity needs.