Write TypeScript like a pro. Typescript Icon

Follow the ultimate TypeScript roadmap.

TypeScript Interfaces: From Type to Interface

A TypeScript Interface is like a more powerful type - so to get a better understanding of interfaces we are going to start off by creating a type and then refactoring it to use an interface.

Introducing types

Let’s start by creating our custom type, which is going to be of an object nature. We’re going to say that the name of the Pizza will be of type string and we’re also going to say that our pizzas are going to have some available sizes - such as 'small', 'medium' or 'large'. These sizes are all going to be a string array string[].

type Pizza = {
  name: string; 
  size: string[]; 
}

Now we want to create a pizza object and mark it upfront as a type of Pizza. We can then later reassign the value.

let pizza: Pizza;

So what we’re going to create is a function called createPizza that will accept a name: string and some sizes: string[]. Let’s assume that you’re using an API at this point where you’d go off to the backend, pass some JSON and then get back from the server a newly created pizza with a dynamic ID.

Angular Directives In-Depth eBook Cover

Free eBook

Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.

  • Green Tick Icon Observables and Async Pipe
  • Green Tick Icon Identity Checking and Performance
  • Green Tick Icon Web Components <ng-template> syntax
  • Green Tick Icon <ng-container> and Observable Composition
  • Green Tick Icon Advanced Rendering Patterns
  • Green Tick Icon Setters and Getters for Styles and Class Bindings

What we’re going to do is use name and sizes, this is the shorthand syntax for creating object literals under the same name as the variables that we want to pass in. So name is the same as name: name.

function createPizza(name: string, sizes: string[]) {
  return {
    name,
    sizes
  }
}

Let’s assume that this is an asynchronous request and inside some other function we are then going to assign the result. So we’re going to say that we want to create the pizza, we need to pass in a name and the sizes that this pizza is available in. Here’s where we’re at so far:

type Pizza = {
  name: string; 
  size: string[]; 
}

let pizza: Pizza;

function createPizza(name: string, sizes: string[]) {
  return {
    name,
    sizes
  }
}

pizza = createPizza('Pepperoni', ['small', 'medium']);

It might be that in a pizza restaurant they have different pizzas or different bases and they’re only available in certain sizes - but when we create a pizza we want to supply these defaults as the arguments. The main purpose here is to start thinking about our interfaces! Let’s now learn about TypeScript’s interface.

TypeScript Interfaces

If you were to hover over the pizza variable you would see it’s of type pizza let pizza: Pizza - but we’re not 100% sure that our createPizza function returns us a pizza. This is known as an inferred type, where we do not describe the type but let TypeScript figure it out for itself.

What we could do now is add Pizza as a type to our function and say that the pizza is going to be returned! Now it’s a guarantee that our function will return us what we’d like, providing the implementation was correct:

function createPizza(name: string, sizes: string[]): Pizza {
  return {
    name,
    sizes
  }
}

What we actually want to do is create an interface instead of a type as it is a preferred approach when we’re dealing with more complex data structures or data sets. To start, we will change our type Pizza to interface Pizza:

interface Pizza {
  name: string; 
  size: string[]; 
}

There’s one interesting thing here, we do not need the equals = operator to assign the type a value, as interface is a special TypeScript type and keyword.

An interface, much like a type, also creates that contractual agreement between perhaps a variable or a data structure. In our case we’re using this pizza variable and we’re saying that at some point this Pizza is then going to be of type pizza.

let pizza: Pizza;

If we were to assign something else (for example if we try to add deal: true) things will break:

function createPizza(name: string, sizes: string[]): Pizza {
  return {
    name,
    sizes,
    deal: true
  }
}

…When we hover over this we will see an error - we’d expect this with a type as well because a type will also pick up on these errors.

With interfaces we can do some interesting things because with object-oriented programming we can do things such as extend particular classes and we don’t get this benefit with simply a type - but we do with an interface!

Let’s remove the deal: true and see what we have.

interface Pizza {
  name: string; 
  size: string[]; 
}

let pizza: Pizza;

function createPizza(name: string, sizes: string[]) {
  return {
    name,
    sizes
  }
}

pizza = createPizza('Pepperoni', ['small', 'medium']);

This is pretty much what we need to know for the basics of learning what an interface is. It’s a special type in TypesScript and it allows us to essentially define the structure or a shape of a particular object/data structure.

BONUS: Interfaces go nicely with classes, and there is a lot of overlap and confusion. We’ve put together a super resource on answering the question “Classes versus Interfaces”.

Combining Interfaces in TypeScript

Let’s create a Pizzas interface which has a data property which will be made up of a Pizza array Pizza[]. This is how you can combine different interfaces, and the same applies to using the type keyword, however we see some additional benefits by using an interface.

interface Pizza {
  name: string; 
  size: string[]; 
}

interface Pizzas {
  data: Pizza[];
}

When we go to use an interface instead of a type, if you hover over interface Pizza it says interface Pizza, which is a token TypeScript will use if and when we write any code that may produce a compilation error. If we were to change this to a type, assign it, and hover over it. We would see something different we would see type Pizza = {name: string; sizes: string[];} so the type Pizza equals an object literal. Another small difference between types and interfaces.

The most important thing to remember is an interface is typically the preferred way that we can create a contract between some kind of variable and its data, and the shape of the data, that we are essentially telling TypeScript is what it looks like.

Learn TypeScript the right way.

The most complete guide to learning TypeScript ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover