To describe the type of an object in Typescript, developers can use either a type alias or an interface. In most situations, both options work almost identical except for their syntactic distinctions. This has confused many developers on what differences do the two methods share and when to choose which. This article aims to answer the first question and believe that it will provide some insights to the second question.
A type alias is just a name
Before discussing the differences between type aliases and interfaces, developers should first know what a type alias is. By using the type keyword to create an type alias, an alias to the type on the right of the assignment operator is created, not a new type.
Since a type alias is just a custom name to a type, it can be used to describe more than just objects, such as primitives and more complex types created from these primitives.
The first difference we will see below is the ability of type alias to describe types of and built of primitives.
Rename primitives
Type aliases can be used to create custom names for primitive types but interfaces cannot. This is more useful for documentation than actual type checking. Since type aliases do not create new types, the compiler treats the custom names as their underlying primitive types.
Let’s look at an example:
Type aliases Celsius and Fahrenheit are custom names for number type. The compiler treats them as number types and does not give warning when function convertCToF is called with argument 9.
Developers from other languages such as Go may get confused by this result because the type keyword is used to create a new type in those languages and the input would need to be casted as the parameter type for the compiler to accept it. TypeScript does not work that way.
Union
Type aliases can be used to describe an union of multiple types but interfaces cannot. Union types are useful for modeling values which can take on multiple different types. Take the following as an example:
Coordinate is an union type of Coordinate2D and Coordinate3D. The TypeScript compiler will not complain as long as the variable fulfills the requirements of either type.
Although interfaces cannot be used to describe union types, they can use unions types inside their own declaration.
Complex types
We can create type aliases of intersection types from union types and thus thus create aliases of complex types. Even though Interfaces can extend from other interfaces or type aliases, but they can only extend an object type or intersection of object types with statically known members which do not include union types.
We have seen a lot of examples of how type aliases are more versatile than interfaces. Nevertheless, There is one feature that is available to interfaces types aliases do not have, which is the ability to extend without redeclaration.
Declaration merging
An interface can be augmented by declaring two or more interfaces using the same name. A type alias, however, cannot be changed after being created.
Let’s look at the example below:
There are two interface declarations of Book and the compiler merged them into one. The end result is a Book interface with both title and author keys.
If you try to do the same with type aliases, you will receive an error of duplicate identifier.
A type alias points to only one type. To extend the type it refers to, you have to create a new type alias and give it a new name.
Library developers who export type declarations may consider using interfaces in case declaration merging is what the library users require.
Conclusion
A type alias is generally more capable than an interface, except that an interface is extendable. If there is a need for type augmentation, you have no choice but choose interfaces. If the type is complex, then type aliases should be picked. If neither cases apply, then you may consider based on code consistency or style preference.