Type vs Interface in TypeScript

type and interface in TypeScript both define object shapes and can often be used interchangeably. However, they behave differently in several ways—declaration merging, extensibility, and support for unions or conditional types.

Basic Syntax

Interface

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

interface User {
  email: string; // Declaration merging
}

Type

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

// Cannot redeclare - will cause error
type User = {
  email: string;
}

Key Differences

1. Declaration Merging

Interfaces can be declared multiple times. TypeScript merges them into a single definition.

Interface supports declaration merging:

interface Window {
  title: string;
}

interface Window {
  ts: TypeScriptAPI;
}

// Result: Window has both title and ts properties

Types cannot be redeclared. A second declaration with the same name causes an error.

Type does not support declaration merging:

type Window = {
  title: string;
}

type Window = {
  ts: TypeScriptAPI;
}
// Error: Duplicate identifier 'Window'

2. Extensibility

Interface uses extends:

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

Type uses intersection (&):

type Animal = {
  name: string;
}

type Dog = Animal & {
  breed: string;
}

3. Computed Properties

Mapped types and computed keys require type. Interfaces do not support this.

Type supports computed properties:

type Keys = 'name' | 'age';

type User = {
  [K in Keys]: string;
}
// Result: { name: string; age: string; }

Interface does not support computed properties directly.

4. Union Types

Union types are only possible with type.

Type can represent unions:

type Status = 'loading' | 'success' | 'error';

Interface cannot represent unions directly.

5. Conditional Types

Conditional types require type. Interfaces do not support them.

Type supports conditional types:

type ApiResponse<T> = T extends string ? string : number;

Interface does not support conditional types.

When to Use What?

Use Interface When:

  • Defining object shapes that might be extended
  • Working with classes (implements)
  • Need declaration merging
  • Creating public APIs
interface DatabaseConfig {
  host: string;
  port: number;
}

interface DatabaseConfig {
  ssl: boolean; // Merged with above
}

class MySQLDatabase implements DatabaseConfig {
  host = 'localhost';
  port = 3306;
  ssl = false;
}

Use Type When:

  • Creating union types
  • Using computed properties
  • Working with conditional types
  • Creating complex type transformations
type Theme = 'light' | 'dark';
type ComponentProps<T> = T extends 'button' ? ButtonProps : DivProps;
type Keys = keyof User;

Performance

Interfaces are generally faster for the TypeScript compiler. Types can be slower with complex conditional types. For simple object shapes, the difference is negligible.

Key Takeaways

  • Interface: Declaration merging, extensibility, classes (implements), public APIs
  • Type: Union types, computed properties, conditional types, complex type logic
  • Performance: Interfaces are faster for the compiler; negligible for simple object shapes
  • Consistency: Choose one approach per project and document it in the style guide