Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 29, 2021 02:34 pm GMT

Type Aliases vs Interfaces in TypeScript

TypeScript provides two ways to create custom types for our data and they include Type aliases and Interfaces. This article will discuss the similarities and differences between them, and the best use cases for each. Let's dive in!

Type aliases

A type alias is basically a name for any type. Type aliases can be used to represent not only primitives but also object types, union types, tuples and intersections. Let's take a look at some examples:

type userName = string;type userId = string | number; // Union typetype arr = number[];// Object typetype Person = {    id: userId; // We're making use of another type alias here    name: userName;    age: number;    gender: string;    isWebDev: boolean;};const user: Person = {    id: 12345,    name: "Tolu",    age: 1,    gender: "female",    isWebDev: true,};const numbers: arr = [1, 8, 9];

Type aliases are declared with the type keyword preceding them. Think of them like regular JavaScript variables that are used to represent certain values. Wherever you use a variable name, it is evaluated to the value that it represents. Type aliases work in a similar manner. Wherever you annotate a type by its alias, the alias will evaluate to the type(s) that it stands for. Like variables, you can't declare the same type alias more than once. Aliases are also never inferred by TypeScript, you have to explicitly annotate them.

Interfaces

Interfaces are another way to name data structures e.g objects. The declaration syntax for interfaces is different from that of type aliases. Let's rewrite the type alias Person above to an interface declaration:

interface Person {    id: userId;    name: userName;    age: number;    gender: string;    isWebDev: boolean;}

Unions and Intersections

A union type is formed from two or more other types, and represents a value that can be any one of them. Intersections allow us to combine multiple existing types into a single type that has all the features of those types. Take the following example:

type Human = {    name: string;    speaks: boolean;};interface Dog {    name: string;    barks: boolean;}type HumanAndDog = Human & Dog; // Intersectiontype HumanOrDogOrBoth = Human | Dog; // Unionlet humanAndDog: HumanAndDog = {    // must have all the properties of Human and Dog    name: "Sparky",    speaks: false,    barks: true,};let humanOrDog: HumanOrDogOrBoth = {    // can have the properties of Human or Dog, or both    name: "Tolu",    speaks: true,};

Type aliases and interfaces can be combined into one type using unions or intersections, but cannot be combined into an interface.

Tuples

Tuples are a way to type arrays with fixed lengths, accounting for every item in said array.

type Mix = [number, string, boolean];const mix: Mix = [1, "banana", true];

In TypeScript, tuples can be declared with types but not interfaces. However, tuples can be used inside interfaces, like this:

interface Mix {    a: [number, string, boolean];}

Declaration merging

If you declare one interface with the same name more than once, TypeScript merges them into one declaration and will treat them as a single interface. This is called declaration merging.

interface Person {    name: string;}interface Person {    age: number;}type Num = numbers;type Num = string; // Duplicate identifier Numlet user: Person = {    // has the properties of both instances of Person    name: "Tolu",    age: 0,};

Declaration merging only works on interfaces. TypeScript will give an error if you declare the same type alias more than once.

Extends

Both type aliases and interfaces can be extended. However, the syntax differs. A derived type alias or interface has all the properties and methods of its base type alias or interface, and can also define additional members.

A type alias can extend another type alias using an ampersand:

type A = { x: number };type B = A & { y: string };

Type aliases can also extend interfaces:

interface A {    x: number;}type B = A & { y: string };

Interfaces can extend type aliases with the extends keyword:

type A = {    x: number;};interface B extends A {    y: string;}

Interfaces can extend other interfaces the same way they extend type aliases. Interfaces can also extend multiple interfaces separated by commas.

interface A {    x: string;    y: number;}interface B {    z: boolean;}interface C extends A, B {    breed: string;}let c: C = {    x: "Sparky",    y: 4,    z: true,};

Interfaces extending classes

TypeScript allows an interface to extend a class. When this happens, the interface inherits the members of the base class, including the private and public members, but not their implementations. This means that when you create an interface that extends a class with private members, only that class or its subclasses can implement that interface. This allows you to restrict the use of the interface to the class or subclasses of the class that it extends.

class Base {    greetFriend() {        console.log(`Hello!`);    }}// Interface extending the Base classinterface Derived extends Base {    giveGist(): void;}// New class that extends Base class and implements the Derived interfaceclass NewClass extends Base implements Derived {    giveGist() {        console.log("I saw this the other day...");    }}const c = new NewClass();c.greetFriend(); // Hello!c.giveGist(); // I saw this the other day...

Implements

TypeScript supports class-based object-oriented programming. As a result, it allows classes to implement both type aliases and interfaces using the implements keyword. An error will be thrown if a class fails to correctly implement it.

// Interface being implemented by a classinterface A {    x: number;    y: number;}class SomeClass implements A {    x = 1;    y = 2;}// Type alias being implemented by a classtype B = {    x: number;    y: number;};class SomeClass2 implements B {    x = 1;    y = 2;}

A class can also implement multiple interfaces separated by commas e.g class A implements B, C {}. Note that a class can not implement or extend a type alias that represents a union type:

type C = { x: number } | { y: number };// ERROR: A class can only implement an object type or intersection of object types with statically known members.class SomeClass3 implements C {    x = 1;    y = 2;}

Its important to understand that an implements clause is only a check that the class can be treated as the interface type. It doesnt change the type of the class or its methods at all. A common source of error is to assume that an implements clause will change the class type - it doesnt!
TypeScript official docs

Which should I use?

Type aliases and interfaces are very similar and you can choose freely between them. Personally, I use type aliases when defining primitive, union, intersection, function or tuple types. However, I make use of interfaces when defining object types or to take advantage of declaration merging.

Conclusion

We have seen the differences and similarities between type aliases and interfaces.

  • Both type aliases and interfaces can be used to describe the shape of an object or a function signature. But the syntax differs.
  • Declaration merging only works on interfaces and not type aliases.
  • You cannot declare a union, intersection or tuple with the interface keyword. However, you can make use of them within an interface.
  • Classes can implement both type aliases and interfaces, but not type aliases that represent a union type.

I hope that you have gained something useful from this article. Kindly leave any questions or additional information in the comment section.

Thanks for reading!


Original Link: https://dev.to/toluagboola/type-aliases-vs-interfaces-in-typescript-3ggg

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To