DEV Community

Cover image for Type ✔ Vs Interface ❌: Why you should chose type over interface in typescript.
Sheraz Manzoor
Sheraz Manzoor

Posted on • Edited on

Type ✔ Vs Interface ❌: Why you should chose type over interface in typescript.

I have come to a solution that you should always use types over interfaces. Let's breakdown why!!

  • Interfaces can only specify objects, but type alias can specify objects and everything else. Let's say we have a single Address field and with type you'll define its type like this:
type Address = string;
const address: Address = '123 Hallway'
Enter fullscreen mode Exit fullscreen mode

But you can't do such stuff with interface like:

interface Address = string; //error
const address: Address = '123 Hallway'
Enter fullscreen mode Exit fullscreen mode

Because interface alias can only define objects. We'll need to change structure altogether if we want to use interface like:

interface Address {
    address: string;
}
const address: Address = {
    address: '12 3 Hallway'
}
Enter fullscreen mode Exit fullscreen mode

That's first problem with interfaces.

  • type alias can define Union types and interface alias can't: Let's user can have multiple or a single address:
type Address = string | string[] ;
const address: Address = '123 Hallway'
const newAddress: Address= ['123 Hallway', 'Flag Plaza']
Enter fullscreen mode Exit fullscreen mode

string | string[] is called a Union type, address can a string, or an array of string.

You can do such stuff with interface alias.

  • types alias can easily use utility types. Interface can do but it will look ugly, for example consider a User Object:
type User = {
    name: string;
    age: number;
    created_at: Date;
}
Enter fullscreen mode Exit fullscreen mode

Now, let's say we have a guest Object, that is not logged in but we can check when it was created (first landed on the page). In this scenario, guest is like a user but not an actual user. We want to have created_at property in Guest from User In type alias we do it like:

     type Guest = Omit<User, 'name' | 'age'>
Enter fullscreen mode Exit fullscreen mode

Technically it is possible with interface but see how it works:

type Guest extends Omit<User, 'name' | 'age'> {}
Enter fullscreen mode Exit fullscreen mode

It works but it is an ugly syntax, isn't it?

  • Sometimes you will need to describe tuples. Here is how we describe it with type alias
type Address = [string, number, string] ;
const address: Address = ['Hallway', 2, 'Abdul Plaza']
Enter fullscreen mode Exit fullscreen mode

But with interface, see how we do it:

type Address extends Array<number | string> {
    0: string
    1: number;
    2: string;
}

const address: Address = ['Hallway', 2, 'Abdul Plaza']
Enter fullscreen mode Exit fullscreen mode

Ugly syntax again.

  • With types alias we can extract types very easily.
const love_bonito ={
    level: 1,
    store_id: 'scad_12hdedhefgfeaa',
    country: ['US','PK','IND'],
    user: {
        user_id: "blah',
        username: 'nishat',
        likes: 421,
    },
};

// let's extract type for love_bonito
type LoveBonito = typeOf love_bonito;

// or even something inside love_bonito
type User = typeOf love_bonito.user;  
Enter fullscreen mode Exit fullscreen mode

Bonus for this is that if we already now level is always one and nothing else, we can do that as well:

const love_bonito ={
    level: 1,
    store_id: 'scad_12hdedhefgfeaa',
    country: ['US','PK','IND'],
    user: {
        user_id: "blah';
        username: 'nishat';
        likes: 421;
    },
} as const

// let's extract type for love_bonito
type LoveBonito = typeOf love_bonito

// or even something inside love_bonito
type User = typeOf love_bonito.user
Enter fullscreen mode Exit fullscreen mode

Now level will be inferred as 1, not as any number.

  • With interface alias you can redeclare an interface,
interface Home {
    rooms: number;
    light_bulbs: 12;
    rented_to: "Abu Turab";
}

interface Home {
   fans: 16;
}

// final type 

interface Home {
    rooms: 3;
    light_bulbs: 12;
    rented_to: "Abu Turab";
    fans: 16;
}
Enter fullscreen mode Exit fullscreen mode

We can't redeclare type alias. You might thing, "Oh! Sheraz, here, this is a plus point of interface", but actually its not!!!

It sounds confusing, to have multiple declarations with the same identifier throughout your codebase. It seems really confusing to me.

Suppose you are working with a team, you knew about type of an object (types declared with interface), but somebody in your team redeclares and changes it, what would you do.

But with type alias this problem is sorted out as well. If you redeclare a type it throws an error

duplicate identifier

  • The name of library is TYPESCRIPT not INTERFACESCRIPT. That might be funky but yeah, why would a company chose to name their library TYPESCRIPT and not IBTERFACESCRIPT. If company is preferring type over interface, so why don't you? 😆

Conclusion

Always prefer types over interfaces. Some devs say that interfaces load faster than types... But that happened in past. Now a days there's no difference regarding performance. There are some use cases where you might need interfaces, but it does not mean that you should interfaces all the time.

Top comments (4)

Collapse
 
miketalbot profile image
Mike Talbot ⭐ • Edited

Why would you Omit name and age from User, rather than extend User from Guest containing created_at?

Interfaces are entirely a way of specifying that an object has a set of properties and methods, they can have no concrete implementation because they are interfaces that may be implemented in different ways by different objects. An object may implement many interfaces, but it can only extend one type. This is what interfaces are for, to allow an object to participate in many different systems by combining functional implementations of standard contracts.

A more advanced case might be:

interface ICreated {
    created_at: Date;
}
interface IUser {
    name: string;
    age: number;
}

class Guest implements ICreated {
     created_at: number;
}

class User extends Guest implements IUser {
  //...
}

Enter fullscreen mode Exit fullscreen mode

With this you have a contract that could be used to retrieve and display created objects using a standard component. No need to know that they are Guests or Users etc.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Brother it'll add name and age properties to User as well. And in guest mode we never have name and properties for user. So it is what it is. You know what I mean?

Collapse
 
miketalbot profile image
Mike Talbot ⭐

Yes, it's messy and the wrong way up.

Thread Thread
 
sheraz4194 profile image
Sheraz Manzoor

Thanks for understanding. You got my point/