Typescript is a superset of JavaScript that incorporates static typing, making detecting errors simpler and producing more maintainable code.
Types and interfaces in Typescript represent two distinct methods for defining the structure and shape of values or objects. They help ensure that variables, objects, arrays, parameters, and function return values match the structure and type set by the developer. This article emphasizes the distinctions between types and interfaces and their appropriate use cases.
Types
Types describe a value type such as string, boolean, number, etc. It enables you to explicitly specify the data type of variables, objects, function parameters, and function return values of functions, for example:
//types in variables
const age: number = 24;
//types in functions
function addNumbers(a: number, b: number): number {
return a + b;
}
You can also use types to describe an object's structure or shape.
//type alias
type User = {
id: string;
firstName: string;
lastName: string;
isAdmin: boolean;
age: number;
};
Interfaces
Interfaces allow you to specify the shape of an object by declaring the properties it should have, along with their types and optionally their accessibility modifiers.
The Differences
Below are some key differences between an interface
and a type
in typescript:
Types can be used to describe primitive types
One key distinction between interfaces and types is that only types can describe primitive types.
In the following code, the type
declarations are suitable for describing the shape of data that isn't an object, but they are not valid for interface declarations.
// Types
// works fine with types
type Status = "pending" | "success" | "error";
type FamousQuotes = string[] | undefined;
//Interface
//Error! parsing error "{" expected
interface IStatus = "pending" | "success"
Interfaces for declaration merging
One advantage interface
has over type
is that you can always reopen them to add more properties. this is not possible when using type
.
interface Person {
name: string;
age: number;
}
// Reopen the Person interface and add a new property
interface Person {
gender: string;
}
const person: Person = {
name: "John",
age: 25,
gender: "Male",
};
console.log(person.name); // Output: John
console.log(person.age); // Output: 25
console.log(person.gender); // Output: Male
When using type
this would throw an error:
type Person = {
name: string;
age: number;
}
// Error: "Duplicate identifier 'Person'"
type Person = {
gender: string;
}
// Error: Object literal may only specify known properties, and 'gender' does not exist in type 'Person'
const person: Person = {
name: "John",
age: 25,
gender: "Male",
};
Interface extension and type union
When working with objects and classes, interfaces offer a more seamless experience, allowing you to extend other interfaces to inherit their properties and methods.
interface Animal {
name: string;
age: number;
eat(): void;
}
interface Dog extends Animal {
breed: string;
bark(): void;
}
const myDog: Dog = {
name: "Max",
age: 3,
breed: "Chihuahua",
eat() {
console.log("Eating...");
},
bark() {
console.log("Woof!");
},
};
console.log(myDog.name); // Output: Max
console.log(myDog.age); // Output: 3
myDog.eat(); // Output: Eating...
myDog.bark(); // Output: Woof!
However, we can perform something known as "intersection types" with types. Intersection types allow you to combine multiple types into a single type with all the properties and methods of each type. This is achieved by using the &
symbol between the different types.
// type
type Animal = {
name: string;
age: number;
eat(): void;
}
type Dog = Animal & {
breed: string;
bark(): void;
}
VS Code IntelliSense performs better with types.
When using types, you can hover over the type declaration, and IntelliSense in VS Code displays the internal properties of that type. However, interfaces only show the name of the declared interface. A related issue can be found on GitHub, as this is a significant factor for some people to prefer using types over interfaces.
IntelliSense on VS Code when using interface
:
IntelliSense on VS Code when using type
:
Comparison Table
The table below compares types and interfaces in TypeScript:
Type | Interface |
---|---|
Syntax | type TypeName = ... |
Declaration | Can be named or anonymous |
Merging | Can be extended using intersection (& ) |
Implementation | Cannot be implemented directly |
Extendable | Cannot extend or be extended |
Intersection | Can be used in intersection types |
Union | Can be used in union types |
Declaration merging | Cannot merge declarations of the same name |
Discriminated union | Cannot be used in discriminated unions |
Function-like | Can define callable and constructible types |
Which should I use for a typescript project?
Often, as someone starting with TypeScript, you might ask yourself, "When should I use 'type' over 'interface' and vice versa?" The comparison above shows that both have different approaches to describing the shape of values and objects in your TypeScript project.
A short, opinionated answer is to use interfaces until you encounter areas where you need to explicitly use types, as interfaces represent how Javascript behaves in a real-world scenario. However, it boils down to a matter of personal preference. This Stackoverflow discussion also highlights different developers' choices and reasons for picking interfaces over types and vice versa.
Conclusion
In this article, we explored some of the differences between types and interfaces in typescript and the best occasions to use one over the other. Ultimately, the decision of whether to use type or interface in a TypeScript project depends on your personal preference and the specific needs of your project. Both have their own strengths and weaknesses, and it's up to you to weigh them and make an informed decision. It's also worth noting that as you gain more experience with TypeScript, your preferences, and needs may change, so don't be afraid to experiment and try different approaches.
Reference
Thanks for reading; I hope you find this article helpful. Cheers
Top comments (0)