So you're working on an Angular application and now you need to know whether you should use a class or an interface when building a model.

Understandable. We've all been there.

In this guide, I'll show you how to reach the right conclusion. 

An Interface

Let's start with an interface.

Here's how you define it:

export interface Contact {
    id: string;
    firstName: string;
    lastName: string;
...
}

It's similar to Java. An interface in TypeScript defines a series of properties and functions. But it doesn't assign values to those properties or implement the functions.

Speaking of implementation, that's what you do with interfaces. You implement them. But you can't instantiate them like you can a class.

In other words, if Contact is an interface, this code won't work:

let contact: Contact = new Contact();

Nope that ain't gonna fily.

If you want to create an empty object that follows the contract of an interface you created, you can go this route:

let contact: Contact = {} as Contact;

Yeah. That will work.

But if you need to do that, it might be a good idea to ask yourself if you should have defined the interface as a concrete class instead.

By the way: you can also extend interfaces just like you extend classes.

So this will work:

export interface SpecialContact extends Contact {
...
}

Again, that assumes Contact is an interface.

Another thing about interfaces: the properties you define in an interface can end with commas or semicolons. I'm a fan of the semicolon route myself since everything else ends with semicolons in TypeScript.

Now here's one reason why interfaces are so attractive: they don't take up any space.

How is that possible? They get removed during the transpiling phase. 

There's a downside to that feature, though. You can't check if a particular object implements that type at runtime.

In other words, you can't do this:

if (contact instanceof Contact) {
...
}

You can, however, check the properties to make a determination about type.

A Class

Now let's take a look at a class. Here's how you define it:

export class Contact {
    id: string;
    customer: boolean = false;
    active: boolean = true;
...
}

As you can see from that code block, I'm defaulting some properties to specific values. Specifically, the booleans customer and active get set once that class is instantiated.

And here's how you instantiate a class:

let contact: Contact = new Contact();

When you do that, the customer and active fields get their respective default values.

If you wanted to go that route with an interface, you could do something like this:

let contact: Contact = { customer: false, active: true } as Contact;

But that starts putting a lot of the burden on the developer who wants to use the interface. Whereas with the class, those properties already get default values with tighter code.

Additionally, you can use a constructor with a class. That's another great way to set some default values.

When to Use Which

Let me start this section by saying that a significant benefit of either choice is that it gives you type-safety.

That's helpful during the development phase when you want to make sure that an object "follows the rules" by using properties only defined in the interface or class.

But beyond that, there are reasons why you might choose one over the other.

Use an interface if:

  • You're looking for a contract with properties and functions, especially if the contract will be used in many places throughout the code
  • When you're using objects that require a base set of properties, such as Person -> Contact -> Customer, each inheriting properties from the parent

Don't use an interface if:

  • You require default values
  • You need to instantiate the type directly
  • You need a type with a constructor
  • You need a type with implemented functions

Use a class if:

  • You need a type with immediate functionality 
  • You need a type with a constructor
  • You need a type with default values
  • You want to create an instance of the type with new
  • You need to do type checking

Don't use a class if:

  • You're looking for type-safety only and don't need to instantiate anything
  • You want the type implemented by other objects

Wrapping It Up

Now you know a little more about classes and interfaces.

Feel free to take what you've learned here and use it to answer that question you're currently asking yourself: "Should I use a class or an interface?"

Have fun!

Photo by Markus Spiske from Pexels