ComparisonComparisons

interface vs type

interface describes an object’s shape and can be extended or merged with another declaration of the same name, while type aliases any type, including unions and tuples.

On this page

Side-by-side comparison

#
  • What it describes

    interface
    The shape of an object: fields and methods
    type
    Any type, e.g. an object, a union, a tuple, a function
  • Extending

    interface
    With the extends keyword
    type
    With the & intersection
  • Two declarations with the same name

    interface
    Merge into one (declaration merging)
    type
    Error: Duplicate identifier 'Name'
  • Unions and tuples

    interface
    Cannot be expressed
    type
    A basic use case
  • Implementation by a class (`implements`)

    type
    Yes, if the alias describes an object
  • Typical use

    interface
    Objects, class contracts, public library APIs
    type
    Unions, tuples, function types, results of utility types

Example

#
TypeScript
interface CourseInterface {
  title: string
  modules: number
}

type CourseType = {
  title: string
  modules: number
}

type Difficulty = 'easy' | 'medium' | 'hard'

const html: CourseInterface = { title: 'HTML and CSS', modules: 11 }
const python: CourseType = { title: 'Python', modules: 12 }
const level: Difficulty = 'medium'

console.log(html.title, python.modules, level)
Result
HTML and CSS 12 medium

Definition and usage

#

Both constructs give a name to the shape of an object, and in most cases you can use either one. The compiler checks them the same way: an object matches a type if it has the required fields of the right types, no matter whether the shape was described with interface or with type.

The differences show up when extending and with types that aren’t objects. You extend an interface with the extends keyword, and you can add fields to it with a second declaration of the same name, because declarations merge. You extend a type alias with the & intersection, and two declarations with the same name are a compile error. Only type can describe a union, a tuple, or a function type, because interface only expresses the shape of an object.

For objects and class contracts, interface is the natural choice, especially in libraries, where declaration merging comes in handy. For unions, tuples, function types, and the results of utility types, you need type. Many teams settle on a simple rule: objects through interface, everything else through type.

Syntax

#
Syntax
interface Name {
  field: Type
}

type Name = Type

More examples

#
Declaration merging only works for interface
TypeScript
interface Config {
  darkMode: boolean
}

interface Config {
  fontSize: number
}

const config: Config = { darkMode: true, fontSize: 16 }
console.log(Object.keys(config))
Result
['darkMode', 'fontSize']
type can’t be reopened with a second declaration
TypeScript
type Profile = { name: string }
type Profile = { age: number }
// Error: Duplicate identifier 'Profile'.
Only type can express a union and a tuple
TypeScript
type Pair = [string, number]
type Status = 'draft' | 'published'

const [title, exp]: Pair = ['Flexbox', 20]
const status: Status = 'draft'

console.log(title, exp, status)
Result
Flexbox 20 draft

Good practices

#
  • If you only need a contract without an implementation, remember that an abstract class is a different tool: an interface has no code, an abstract class can.
  • Name interfaces after what the object is (User, Course), without an I prefix.
  • Settle on one convention for plain objects in the project, so you don’t have to think it over at every declaration.

Related entries

#

Spotted a mistake or missing an example? Write to us.