跪拜 Guibai
← Back to the summary

TypeScript's type vs. interface: The Rules That Actually Matter

Abstract: type and interface are the most confusing concepts in TypeScript and a must-ask in interviews. Many developers mix them casually in code without understanding their underlying differences. This article uses code examples to clarify their similarities, core differences, and how to choose between them in real-world development.

Introduction

When first learning TypeScript, you face two ways to define object types: interface and type. Many feel they are similar and just pick one at random. But interviews often ask: What is the difference between type and interface?

Knowing only that "both can define objects" is far from enough. They have clear differences in syntax capabilities, merging behavior, and function descriptions. After reading this, you won't hesitate when writing TypeScript.

1. Similarities: Scenarios Where Both Are Interchangeable

Both can describe object structures and function types, and both can constrain variables, function parameters, and return values.

1. Describing Plain Objects

typescript

// interface version
interface UserInterface {
  name: string
  age: number
}

// type version
type UserType = {
  name: string
  age: number
}

// Usage is completely identical
const u1: UserInterface = { name: "张三", age: 18 }
const u2: UserType = { name: "李四", age: 20 }

2. Describing Function Types

Both can constrain functions, just with different syntax, which will be detailed later.

3. Both Support Type Extension (Inheritance)

typescript

// interface extension
interface Animal {
  name: string
}
interface Dog extends Animal {
  bark(): void
}

// type extension
type AnimalT = { name: string }
type DogT = AnimalT & { bark(): void }

Summary: For defining plain objects, both are interchangeable in most scenarios.

2. Core Differences (Interview Focus)

1. Declaration Merging: A Capability Unique to interface

interface supports multiple declarations with the same name; TypeScript automatically merges all properties. type strictly forbids duplicate declarations and throws a compilation error.

✅ interface merging example

typescript

interface User {
  name: string
}
// Declare the same interface again, properties merge automatically
interface User {
  age: number
}

// Final User = { name:string; age:number }
const user: User = { name: "小明", age: 22 }

❌ type duplicate declaration throws an error directly

typescript

type User = { name: string }
type User = { age: number } 
// Error: Duplicate identifier 'User'.

This feature is very important! When patching third-party library types or extending global types, you can only use interface. type cannot do this.

2. Whether Non-Object Types Can Be Described

interface can only describe reference structures like objects, functions, and classes. It cannot write primitive types, union types, or tuples. type is a type alias that can give any type a name, making it more powerful.

typescript

// ✅ type supports
type Status = "success" | "error" // union type
type NumAlias = number // primitive type alias
type Point = [number, number] // tuple

// ❌ interface — all of the following throw errors
interface Status = "success" | "error"
interface NumAlias = number
interface Point = [number, number]

3. Syntax Differences for Function Types

Both can write function types, but the syntax differs. For simple functions in daily development, type is more convenient.

interface: call signature syntax, written inside curly braces

typescript

interface AddFn {
  (a: number, b: number): number
  desc: string // Advantage: directly attach extra properties to the function
}

const add: AddFn = (x, y) => x + y
add.desc = "addition function"

type: arrow syntax, concise and intuitive

typescript

type AddFn = (a: number, b: number) => number

// If you need to attach properties to a function, you must use & intersection, which is cumbersome
type AddFnWithProp = ((a: number, b: number) => number) & { desc: string }

Note:

  • interface defines functions: return value uses :
  • type defines functions: return value uses =>

4. Extension Conflict Behavior Differs

typescript

// interface conflict, throws error directly
interface Base { id: number }
interface A extends Base { id: string }

// type conflict, no error, id becomes never
type BaseT = { id: number }
type B = BaseT & { id: string }

3. How to Choose in Development? Practical Advice

  1. Need declaration merging, extending third-party global types → choose interface

For example, to attach custom properties to window, you can only use interface.

typescript

interface Window {
  myGlobal: string
}
window.myGlobal = "123"
  1. Writing union types, tuples, primitive type aliases → must use type

interface cannot do this; there is no alternative.

  1. Plain function types, no need to attach extra properties → prefer type, arrow syntax is cleaner
  2. Plain object types, no special requirements: either works

Community convention: prefer interface for exposed library APIs; prefer type for internal business types.

4. Interview Cheat Sheet (Condensed Version)

Interview question: Explain the difference between type and interface.

Similarities: Both can describe object and function structures; both can constrain variables, parameters, and return values; both support type extension.

Differences:

  1. interface supports declaration merging; type cannot be declared repeatedly;
  2. interface uses extends for extension; type uses intersection &;
  3. type can define unions, tuples, and primitive type aliases; interface only supports object-like structures;
  4. Function syntax differs: interface uses call signatures, type uses arrows; type is more concise for simple functions;
  5. On property conflicts, interface throws an error directly; type produces never.

Conclusion

Many people write TypeScript by feel and choose randomly. Understanding the capability boundaries of both will make your types more standardized. Remember: it's not about which is better, but which is more suitable for the current scenario.

Complete Test Code Block

typescript

// 1. interface object extension
interface Animal {
  name: string
}
interface Dog extends Animal {
  age: number
}

// 2. type object extension
type AnimalType = { name: string }
type DogType = AnimalType & { age: number }

// 3. interface function type
interface AddInterface {
  (a: number, b: number): number
  info: string
}

// 4. type function type
type AddType = (a: number, b: number) => number

// 5. interface declaration merging
interface User {
  name: string
}
interface User {
  age: number
}
const user: User = { name: "测试", age: 18 }