Common
Both can define a data type.
Types aliases in Typescript mean "a new for any type".
type MyNumber = number;
type StringOrNumber = string | number;
type User = {
id: number;
name: string;
email: string;
}
An interface defines a contract that an object must adhere to.
interface Person {
name: string;
address: string;
}
Difference
1. Primitive Type
Primitive types are inbuilt types in TypeScripts. They include number, string, boolean, null, and undefined types.
Type alias can be used to define a alias for a primitive type as below.
type MyString = string;
type NullOrUndefined = null | undefined;
But, interface can not be used to define a alias for a primitive type.
2. Union types
Union types can describe values that can be one of several constant and create unions of various primitive, literal or complex types.
type Computer = 'Desktop' | 'Laptop' | 'Tablet';
Union type can only be defined using type. Interface cannot define a union type. But it is possible to create a new union type from several interfaces:
interface Laptop {
cpu: string;
ram: number;
storage: number;
}
interface SmartPhone {
number: string;
}
type Mobile = Laptop | Phone;
3. Function types
In Typescript, a function type represents a function's prototype. Type alias defines function prototype like this:
type Add = (num1: number, num2: number) => number;
You can also use an interface to do samething:
interface IAdd {
(num: number, num2: number): number;
}
As you can see both type and interface are similar except for a syntax difference. And type is preferred to define a function prototype.
It is also because type has more capability to define function type. Here's an example:
type Watch = 'Mechanical' | 'Electrical';
type WindUp = (cycle: number) => void;
type Recharge = () => void;
type RefillWatch<W extends Watch> =
W extends 'Mechanical' ?
WindUp : W extends 'Electrical' ?
Recharge : never;
const windUp: RefillWatch<'Mechanical'> = (watch, cycle) => {
// Something to wind up the spring of the watch
}
const recharge: RefillWatch<'Electrical'> = (watch) => {
// Something to charge the watch
}
4. Merging of declarations
Merging of declarations is a feature for only interface.
interface Computer {
cpu: string;
}
interface Computer {
ram: string;
}
const mine: Computer = {
cpu: 'Core i-9 9900',
ram: '32GB',
};
5. Extends and intersection
An interface can extend original interface:
interface Computer {
cpu: string;
ram: string;
}
interface Laptop extends Computer {
battery: string;
}
You can also get same result with type alias:
type Computer = {
cpu: string;
ram: string;
}
type Laptop = Computer & {
battery: string;
}
You can also extends an interface from a type alias:
type Computer = {
cpu: string;
ram: string;
}
interface Laptop extends Computer {
battery: string;
}
But you cannot extend an interface from a union type:
type Watch = 'Mechanical' | 'Electrical';
interface MoreWatch extends Watch {
brand: string;
}
Type aliases can extend interfaces using the intersection like this:
interface Watch {
brand: string;
}
Type ElectricWatch = Watch & {
battery: string;
}
6. Handling conflicts
You cannot extend an interface with same property key like this:
interface Watch {
refill: () => void;
}
interface Watch {
refill: (cycle: number) => void;
}
But you can extend a type alias with same property key like this:
type Person = {
getPermission: (id: string) => string;
};
type Staff = Person & {
getPermission: (id: string[]) => string[];
};
const AdminStaff: Staff = {
getPermission: (id: string | string[]) => {
return (typeof id === 'string' ?
'admin' : ['admin']) as string[] & string;
}
}
If you extend a type alias like this, the model property type would not be determined because it can't be both string and number at the same time:
type Computer = {
model: string;
};
type Laptop = Computer & {
model: number;
};
// error: Type 'string' is not assignable to type 'never'.(2322)
const mine: Laptop = { model: 'Dell' };
7. Implementing class
In Typescript, you can implement a class using either an interface or a type alias:
interface Person {
name: string;
greet(): void;
}
class Student implements Person {
name: string;
greet() {
console.log('Hello');
}
}
type Pet = {
name: string;
greet(): void;
};
class Cat implements Pet {
name: string;
greet() {
console.log('Mew');
}
}
But you cannot implement a class that extends a union type:
type Key = { key: number; } | { key: string; };
// can not implement a union type
class PrimaryKey implements Key {
key = 1
}
8. Tuple type
In Typescript, the tuple type can express an array with a fixed number of elements, while each element has its data type:
type State: [name: string; setter: (value: string) => void];
If you want to declare a tuple type with an interface, you can do it like this:
interface IState extends Array<string | (value: string) => void> {
0: string;
1: (value: string) => void;
}
9. Benefits of the type alias than the interface
Here's an example of the advanced type feature that the interface cannot achieve:
type Person = {
name: string;
address: string;
}
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type PersonType = Getters<Perso>;
// type PersonType = {
// getName: () => string;
// getAddress: () => string;
// }
Conclusion
In this post, I have explained the features of the type alias and the interface in Typescript.
As above the type alias has more powerful features than the interface. So I recommend to use the type alias when coding.
Top comments (0)