Back
TypeScript Interface vs Type: Differences and Best Use Cases
Learn the key differences between TypeScript interface and type, and discover when to use each for defining data structures in your TypeScript projects.
Developers’ preference for a statically typed language increased the usage of TypeScript in modern web development, especially as a replacement for JavaScript. A major advantage of using TypeScript over JavaScript is that TypeScript uses static typing, which performs type-checking at compile time.
There are two ways of defining types in TypeScript: types and interfaces. To best use TypeScript, developers must know which interfaces and types to use and when. This blog post will discuss TypeScript interface vs type, how they can be used to define types, and how to use each.
Types in TypeScript
If you have prior experience coding in a statically typed language, then the concept of types will be familiar. Types in TypeScript are used to define the properties of data we’re working with, particularly the type. The fundamental types include string, boolean, number, and array.
With type aliases, you can create a custom name for existing types. Type aliases are created using the type keyword, which allows you to change the name of a type without explicitly creating a new type. Let’s see how this works:
With the type keyword, I named the alias company, which is of the string type. I also created object and union type aliases and specified their data types.
Interfaces in TypeScript
Interfaces are primarily used to describe the shape of data, which includes its properties and methods. Interfaces define contracts that an object or class must adhere to. They play a crucial role in maintaining a consistent type structure across your codebase. Here’s an example where we define the structure of an object:
Here, I created an interface named Company and then defined the data type to expect for each property. First, the name and description are of the string type, the isBest property is of Boolean type and the rank property is a number type. What we have done here is create the shape of the data the companyObject
must adhere to.
As we defined using the interface keyword, the name property has the value “Pieces for Developers”, which is a string type. Next, we include the value of the description property which is “an on-device AI coding assistant and snippet manager”, also of string type. For the isBest property, we set the value to true, which confirms Pieces is the best AI coding assistant. Finally, we set the value of the rank property to 1, a number type. We see that all the values in the companyObject conform to the initially defined types.
Differences between Types and Interfaces
Based on what we have discussed so far, the major difference between type and interface in TypeScript is how they represent data, but that’s not all. In this section, we will further explore type vs interface in TypeScript and how they can be used to perform actions such as declaration merging, defining primitive types, defining union types, defining tuples, implementing classes, and extending the properties or methods of a class. Let’s dive in!
Declaration Merging
When two interfaces with the same name (but different properties) are declared, the TypeScript compiler automatically merges the two declarations. Here’s an example:
Here, the two Company interface declarations are automatically merged by the TypeScript compiler. This is not possible with the type keyword. Suppose you define multiple declarations with the same name using the type keyword:
The code above does not run successfully, it throws an error that says Duplicate identifier 'Company'. This shows that declaration merging only works with TypeScript interfaces.
Primitive Types
Primitive types refer to the fundamental types used in TypeScript. They include string, boolean, number, etc. Type aliases are often used to represent these primitive types. Consider the example below:
Interfaces, on the other hand, cannot be used to represent a primitive type. They can only be used for an object type. So, to define a primitive type, you should use the type keyword.
Union Types
Sometimes, you may need to create values that can be of multiple types, this can be achieved with union types. Union types can be defined using type aliases. Let’s see an example:
Here, we created a profileName that can be either a string type or a number type. Union types cannot be directly created using interfaces. You can, however, create a union type by combining two interfaces. Here’s an example:
Tuples
Tuples allow you to represent a fixed set of values (can be of different types) in an array. They provide a more structured way to deal with values of different data types. A tuple has a fixed length and an ordered position for each element, so object declarations must conform to the exact length of the array and must be in the exact arrangement. Consider this example to have a better understanding of Tuples:
Here, we have a tuple created with three elements in an array. We can then create an object that follows the structure defined above:
The elements in the array conform to the data types initially defined. “Ella” is of string type and is in the first position in the array, “26” is of number type and is in the second position, “true” is of boolean type and is in the third position.
Implementation of Classes
Classes in TypeScript can be implemented using either type alias or interface. Let’s see how to implement classes using type aliases or interfaces:
The syntax for the implementation is fairly similar; the only downside is that union types cannot be implemented with class.
Extensions and Intersections
TypeScript allows you to extend the properties and methods of a particular interface type to a new interface. This is only for interfaces and can be implemented using the extends keyword. We can create a new interface by extending an existing interface, here’s an example:
Here, we extended the properties from the Company interface and created a new SupportTeam interface. This new interface contains the properties of the parent interface and the new interface created. Type aliases do not provide an out-of-the-box functionality to extend classes. We can, however, use the intersection (&) operator to combine multiple types into one. Here’s an example:
The properties of type aliases and interfaces can be extended, however, the manner of implementation is different.
TypeScript Interface vs Types: Which Should You Use?
We’ve discussed TypeScript type vs interface, and how they differ. We also discussed how the usage of type aliases, instead of interfaces, could throw an error. Now, let’s explore specific instances when you should use types and interfaces. Here are some use cases of types:
To define primitive types
To overload functions
To use advanced features such as mapped types, utility types, conditional types, etc.
To create aliases for complex types such as unions and intersections
To define tuple types
Types, compared to interfaces, provide a wider range of type handling. Here are some use cases of interfaces:
Defining object methods or object shapes
Merging declarations
Extending properties or methods of interfaces
Conclusion
As a developer, it’s highly beneficial to follow best practices when coding. This helps create scalable applications, make code documentation easier, and foster collaboration among developers. In this blog post, we discussed TypeScript interface vs type, their differences, and the specific use cases of each. Happy coding!