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.
Side-by-side comparison
#What it describes
Extending
Two declarations with the same name
Unions and tuples
Implementation by a class (`implements`)
Typical use
Example
#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)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
#interface Name {
field: Type
}
type Name = TypeMore examples
#interface Config {
darkMode: boolean
}
interface Config {
fontSize: number
}
const config: Config = { darkMode: true, fontSize: 16 }
console.log(Object.keys(config))['darkMode', 'fontSize']
type Profile = { name: string }
type Profile = { age: number }
// Error: Duplicate identifier 'Profile'.type Pair = [string, number]
type Status = 'draft' | 'published'
const [title, exp]: Pair = ['Flexbox', 20]
const status: Status = 'draft'
console.log(title, exp, status)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 anIprefix. - 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.