Skip to content
This repository was archived by the owner on Feb 9, 2025. It is now read-only.
This repository was archived by the owner on Feb 9, 2025. It is now read-only.

TypeScript: types vs. interfaces #64

Open
@jhnns

Description

@jhnns

TypeScript has two ways to describe the shape of an object: a type alias and an interface. I would like to collect some arguments for the discussion around types vs interfaces.

Historically, interfaces were more powerful which is why a lot of people went with interfaces. But nowadays the differences are not that big anymore. To summarize:

  • Type aliases don't create new names in error messages (not correct anymore)
  • Type aliases cannot be implemented by classes (not correct anymore, only union types are not implementable which are impossible to do with interfaces anyway)
  • Two type aliases with the same name throw an error whereas two interfaces with the same name are merged into a single one (known as "Declaration merging"). This is an advantage of interfaces when dealing with third-party libraries, but can be a disadvantage if there is a name conflict in the current file (Example).
  • Mapped types via Key in AllowedKey are impossible with interfaces (Example)
  • Interfaces can reference itself in its definition via this. Type aliases need to use the type alias name (which can be impossible sometimes TypeScript 3.7 supports recursive types) (Example)
  • Interfaces have the polymorphic this type. Some inheritance patterns cannot be expressed via types (Example)
  • CodeLens In VSCode has better support for interfaces (not correct anymore, see below)
  • Intersection types can create types that are impossible to implement, whereas interfaces will show an error at the extends keyword (Example)
  • On the other hand, types can express intersection types that are impossible to express with interfaces (e.g. merging of types that overlap, like string and "some string") (Example)
  • Interfaces must always have a name. Types can be inlined without giving them a name, e.g. when instantiating the React.FC<{}> generic.

Personally I prefer type aliases because of the following reasons:

1. It's less to write (and less to read)

type A = AnotherType & ADifferentType & {
    a: boolean;
};

// vs

interface A extends AnotherType, ADifferentType {
    a: boolean;
}

Ok, that's not a big difference, but look at the next example:

const Component: React.SFC<Readonly<{
    a: boolean;
    b: string;
    c: number;
}>> = ({a, b, c}) => {};

// vs

interface ComponentProps {
   readonly a: boolean;
   readonly b: string;
   readonly c: number;
}

const Component: React.SFC<ComponentProps> = ({a, b, c}) => {};

2. It's a single way to handle types

One problem I see is that you can't really use interfaces in an ergonomic way when you want to use TS' utility types, like Readonly:

// we have to create a mutable interface first
// before we can create a readonly type :(
interface A {}
type B = Readonly<A>; 

type on the other hand provides a single way to define and merge types as you like. For instance, union types are impossible with interfaces, but straightforward with type aliases.

In general I think it's impossible to have a big project without using type, but it's possible to have a big project without interface. We used type aliases in a big project and never really missed interfaces.


For me there are only three valid reasons for interfaces:

Nicer hints in VSCode

Maybe they will improve it for type as well. I don't see a reason why this is only implemented for interfaces. It's possible to get a CodeLens for type references though (see below).

Third-party libs

It's often recommended to use interfaces for third-party libs because of declaration merging. This makes it possible to extend the type with own properties.

While this is true for libraries like Express that provide a single Request or Response object which is extended by middlewares, I don't think that it's true for third-party libraries that don't support this kind of API. Personally I even think that it's bad practice to have an API where objects can be extended by everyone. So why should I use interfaces if I don't want to support this kind of usage anyway.

OO programming style

If your project/team heavily uses an object-oriented programming style interfaces make much more sense.


What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions