Sometimes you find yourself using TypeScript and wonder whether you should pick and interface
or a type
.
The keyboard cursor is blinking.
The clock is ticking.
And you haven't written the t
for type
, or the i
for interface
yet.
If this has happened to you, I have something to tell ya': at the end of this post, you'll know exactly which one to choose and never hesitate again in this specific situation.
Differences
In general, both declarations are pretty much interchangeable. Albeit there are two big differences:
-
interface
can be augmented through declaration merging, whereastype
can't -
type
can extend union types, whereasinterface
can't
Let's dissect these two points:
Diference #1
What's declaration merging? If you ever used Ruby
, you can do these kind of class
augmentations:
class Dog
def bark
puts 'woof-woof!'
end
end
# A few lines of code below
class Dog
def bark2
puts 'arf-arf!'
end
end
This is called monkey patching. You can basically re-open a class
and add more methods to it, or even override them.
In TypeScript there's a similar concept called declaration merging:
“declaration merging” means that the compiler merges two separate declarations declared with the same name into a single definition. This merged definition has the features of both of the original declarations. Any number of declarations can be merged; it’s not limited to just two declarations.
For the scope of the post, we are only interested in interface merging.
What can we do with it?
In a similar way as monkey patching, we can join partial interface declarations with the same name into a single one.
For example, we can have:
interface Dog {
bark(): void
}
interface Dog {
bark2(): void
}
And then, using it as a single merged interface:
const doggyDog: Dog = {
bark() {
console.log('woof-woof!')
},
bark2() {
console.log('arf-arf!')
}
}
If we use type
, we'll get a duplication error:
type Dog = {
bark(): void
}
type Dog = {
bark2(): void
}
| Duplicate identifier 'Dog'.
Diference #2
The ability of type
is that it can extend union types.
What are union types?
If we think types as sets of values, we might want values that belong to the type A
, and perhaps also to another type B
.
We can achieve that in TypeScript unifying these two types using the vertical bar |
as A | B
.
With this, we've created a new type whose values belong to both sets.
For instance, if we have:
type Dog = {
bark(): void
}
type Cat = {
meow(): void
}
type CatDog = Cat | Dog
Then, we can extend this type
declaration:
type Pet = CatDog & {
name: string
}
On the other hand, if we use interface
it'll complain:
interface Pet extends CatDog {
name: string
}
| An interface can only extend an object type or intersection of object types with statically known members.
For more info about this error you can check this GitHub issue.
Conclusion
OK, so now I know the differences... but which one should I use?
I'd say it'll depend on your particular case.
If you want to have types that are rather complex and flexible, then you should use type
.
If you want more readability in the code, avoid extending union types, or you are prototyping code that might require augmentation throughout the codebase, then you should consider using interface
.
From my experience, I'm currently working on a project that started using type
for everything, and we are stick to it without needing to use interface
at all.
Remember that, in most cases, type
is more capable than an interface
.
Top comments (0)