Skip to content

Interfaces over aliases

Interfaces and type aliases in TypeScript are very similar, and you can use them interchangeably. However, some differences tip the scales in favor of interfaces.

Why prefer interfaces

First of all, errors in interfaces produce better error messages, for example:

// Owl is a type alias (see example link)
const owl: Owl = { wings: 2, nocturnal: true };
// Chicken is an interface
const chicken: Chicken = { wings: 2, colourful: false, flies: false };
// Alias error:
owl = chicken;
//=> Type 'Chicken' is not assignable to type 'Owl'.
//=> Property 'nocturnal' is missing in type 'Chicken' but required in type '{ nocturnal: true; }'.
// Interface error:
chicken = owl;
//=> Type 'Owl' is missing the following properties from type 'Chicken': colourful, flies

Another one is extending interfaces has better performance than intersecting aliases.

Finally, while type aliases give more flexibility, it’s a bad thing when it comes to designing a database schema. Interfaces will make your code easier to read and maintain.

They will even force you to use best practices, as with the field groups:

For example, this would be the most intuitive way to define a post with a soft delete when using type aliases:

type Post = {
text: string;
} & (
| {}
| {
deletedAt: Date;
deletedBy: string;
}
);

However, interfaces don’t support intersections, so you’ll have to use field groups that are ultimately better readability and type-safety-wise:

interface Post {
text: string;
deleted?: SoftDeleted;
}
interface SoftDeleted {
at: Date;
by: string;
}

Read more about field groups

When to use type aliases

While interfaces are preferable, type aliases are still viable when defining a database schema, for example:

interface Post {
text: string;
state: PostState;
}
// We use type alias to define a union type
type PostState = PostStateActive | PostStateDeleted;
interface PostStateActive {
type: "active";
}
interface PostStateDeleted {
type: "deleted";
at: Date;
}

In the example above, we use a type alias to define a union type PostState, which helps us define variable post state.

Read about the differences between aliases and interfaces