Execute Program

Everyday TypeScript: Interfaces

Welcome to the Interfaces lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • We've seen object types like type User = { name: string }. In this lesson we'll learn about interfaces, which give us another way to define those same types. They also offer some advantages over using the type keyword.

  • The next example has User1 and User2 types describing the same object type. We define User1 as an object type and User2 as an interface. We can assign values of one type to the other with no problems.

  • >
    type User1 = {
    name: string
    };

    interface User2 {
    name: string
    }

    const user1: User1 = {name: 'Amir'};
    const user2: User2 = user1;
    user2.name;
    Result:
    'Amir'Pass Icon
  • Why bother with interfaces when we already have object types? One reason is the way that naming conflicts are handled. If we've already defined a type named User and we try to define another type with the same name, that's a type error. This matches how other kinds of declarations work, including functions, classes, and variables.

  • >
    type User = {
    name: string
    };
    type User = {
    email: string
    };
    Result:
    type error: Duplicate identifier 'User'.Pass Icon
  • We can avoid that error by giving the types separate names. Then we can combine them as an intersection type with & to get a single object type.

  • >
    type HasName = {
    name: string
    };
    type HasEmail = {
    email: string
    };

    type User = HasName & HasEmail;

    const user: User = {
    name: 'Amir',
    email: 'amir@example.com',
    };

    user;
    Result:
  • Now let's consider the same User type, but defined as an interface. Defining two interfaces with the same name doesn't cause an error. Instead, we get "declaration merging": all interface definitions with the same name are merged into a single interface. It's as if the compiler implicitly intersects them for us.

  • >
    interface User {
    name: string
    }
    interface User {
    admin: boolean
    }

    let amir: User = {
    name: 'Amir',
    admin: true,
    };
    amir;
    Result:
    {name: 'Amir', admin: true}Pass Icon
  • We'll see more features of interfaces in future lessons. For now, here are some reasons to consider using interfaces instead of the type keyword:

    • Interfaces can produce better error messages in some cases.
    • Interfaces sometimes compile faster than object types.
    • The official TypeScript documentation uses interfaces in its examples, so you'll see a lot of interfaces even if you don't use them.
    • The TypeScript team endorses interfaces. For example, Daniel Rosenwasser, TypeScript's Program Manager, has publicly endorsed them over object types: "my take is that it should really just be interfaces for anything that they can model" (source).
  • You can define many types using either interfaces or the type keyword. Neither choice will cause catastrophic problems, so it's a matter of preference. Each team should collectively decide whether they want to favor object types or interfaces.

  • Here's a code problem:

    This code example tries to define two types named User. Change the types into interfaces. Then the code example will work because the interfaces will be merged automatically.

    (Note that interfaces don't have an = before the {. This is different from the usual object type syntax, type User = { ... }.)

    interface User {
    name: string
    }
    interface User {
    email: string
    }
    const user: User = {
    name: 'Amir',
    email: 'amir@example.com',
    };

    user;
    Goal:
    {name: 'Amir', email: 'amir@example.com'}
    Yours:
    {name: 'Amir', email: 'amir@example.com'}Pass Icon