DEV Community

Cover image for Differences between interface and type in TypeScript
Nicolas Del Piano
Nicolas Del Piano

Posted on

Differences between interface and type in TypeScript

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:

  1. interface can be augmented through declaration merging, whereas type can't
  2. type can extend union types, whereas interface 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.

References

Top comments (0)