Typescript extends and implements

TypeScript Extends VS Implements: Understanding The Differences And When To Use Each

TypeScript Extends VS Implements: Understanding The Differences And When To Use Each

This article provides an in-depth exploration of TypeScript’s class and interface system, focusing on the «extends» and «implements» keywords. It covers the differences between «extends» and «implements,» their use cases, and provides examples of their implementation.

Important disclosure: we’re proud affiliates of some tools mentioned in this guide. If you click an affiliate link and subsequently make a purchase, we will earn a small commission at no additional cost to you (you pay nothing extra). For more information, read our affiliate disclosure.

Introduction To TypeScript Class And Interface System

TypeScript is a superset of JavaScript that provides developers with a type system for building robust and scalable applications. One of the key features of TypeScript is its class and interface system, which allows developers to build complex object-oriented applications with ease.

In TypeScript, classes are blueprints for creating objects that encapsulate data and behavior. They are similar to classes in other object-oriented languages like Java and C#, but with some added benefits, such as optional typing and support for modern JavaScript features like arrow functions and template literals.

Interfaces, on the other hand, are a way to describe the shape of an object without actually implementing any behavior. They define a set of properties and methods that an object must have in order to be considered an instance of that interface. Interfaces are used to enforce contracts between different parts of a system and help ensure that they work together seamlessly.

Читайте также:  Save byte array to file in java

Together, classes and interfaces form the backbone of TypeScript’s type system. They allow developers to write more maintainable and robust code by encapsulating data and behavior, enforcing contracts between different parts of the system, and providing clear and concise documentation for APIs.

In the rest of this article, we’ll explore two key concepts in TypeScript’s class and interface system: extends and implements. These keywords allow us to build complex applications by reusing code and implementing interfaces, and understanding when and how to use them is key to becoming a proficient TypeScript developer.

Understanding Extends And Implements

Differences Between Extends And Implements

  • «extends» is used to create a subclass that inherits properties and methods from a parent class, while «implements» is used to create a class that implements an interface.
  • When a subclass extends a parent class, it inherits all of its public and protected properties and methods. When a class implements an interface, it must provide an implementation for all of its properties and methods.
  • Subclassing with «extends» is a form of inheritance, while implementing with «implements» is a form of interface implementation.

One of the key differences between «extends» and «implements» is the type of relationship they create between classes. When a class extends another class, it creates a subclass-superclass relationship, where the subclass inherits properties and methods from the superclass. This is a form of inheritance, and it allows developers to reuse code and avoid duplicating functionality across multiple classes.

When a class implements an interface, on the other hand, it creates a class-interface relationship, where the class must provide an implementation for all of the properties and methods defined in the interface. This is a form of contract enforcement, and it allows developers to ensure that different parts of a system work together seamlessly by adhering to a common set of rules.

Here’s an example that illustrates the difference between «extends» and «implements»:

class Animal < constructor(public name: string) <>speak() < console.log(`$makes a noise.`); > > interface Pet < breed: string; play: () =>void; > class Dog extends Animal implements Pet < constructor(name: string, public breed: string) < super(name); >play() < console.log(`$plays fetch.`); > bark() < console.log(`$barks.`); > > const dog = new Dog('Fido', 'Golden Retriever'); dog.speak(); // Output: "Fido makes a noise." dog.play(); // Output: "Fido plays fetch." dog.bark(); // Output: "Fido barks."

In this example, we have an Animal class and a Pet interface. We then define a Dog subclass that extends the Animal class and implements the Pet interface. This allows the Dog class to inherit the speak method from the Animal class and implement the breed and play properties and methods from the Pet interface.

When we create a new instance of the Dog class and call its speak , play , and bark methods, it outputs «Fido makes a noise.», «Fido plays fetch.», and «Fido barks.»

Use Cases For Each Keyword

  • Use «extends» when you want to create a new class that extends the functionality of an existing class. This allows you to reuse code and avoid duplicating functionality across multiple classes. For example, you might extend a base class to create more specific subclasses that have additional functionality or properties.
  • Use «implements» when you want to enforce a contract between different parts of a system. This allows you to define a set of properties and methods that a class must implement in order to conform to that interface. For example, you might implement an interface to ensure that all classes that use a certain API have the necessary properties and methods.
  • Creating a subclass that extends the functionality of a parent class.
  • Reusing code and avoiding duplicating functionality across multiple classes.
  • Adding new properties and methods to a subclass.

Here’s an example that illustrates a common use case for «extends»:

class Shape < constructor(public color: string) <>draw() < console.log(`Drawing a $shape.`); > > class Circle extends Shape < constructor(public radius: number, color: string) < super(color); >area() < return Math.PI * Math.pow(this.radius, 2); >> const circle = new Circle(5, 'blue'); circle.draw(); // Output: "Drawing a blue shape." console.log(`The area of the circle is $.`); // Output: "The area of the circle is 78.53981633974483."

In this example, we have a Shape class that has a color property and a draw method. We then define a Circle subclass that extends the Shape class and adds a radius property and an area method.

When we create a new instance of the Circle class and call its draw and area methods, it outputs «Drawing a blue shape.» and «The area of the circle is 78.53981633974483.»

  • Enforcing a contract between different parts of a system.
  • Ensuring that classes adhere to a common set of rules.
  • Defining a set of properties and methods that a class must implement.

Here’s an example that illustrates a common use case for «implements»:

interface Employee < name: string; id: number; salary: number; calculateBonus: () =>number; > class Developer implements Employee < constructor(public name: string, public id: number, public salary: number) <>calculateBonus() < return this.salary * 0.1; >> class Manager implements Employee < constructor(public name: string, public id: number, public salary: number, public teamSize: number) <>calculateBonus() < return this.salary * 0.2; >> const developer = new Developer('John Doe', 1, 50000); const manager = new Manager('Jane Smith', 2, 75000, 5); console.log(`$'s bonus is $$.`); // Output: "John Doe's bonus is $5000." console.log(`$'s bonus is $$.`); // Output: "Jane Smith's bonus is $15000."

In this example, we have an Employee interface that defines a set of properties and a calculateBonus method. We then define a Developer class and a Manager class that both implement the Employee interface, ensuring that they both have the necessary properties and methods to be considered employees.

When we create a new instance of the Developer class and the Manager class and call their calculateBonus methods, it outputs «$5000.» and «$15000.», respectively.

Code Reuse And Inheritance

Code reuse and inheritance are key concepts in object-oriented programming that allow developers to write more maintainable and scalable applications. Inheritance is a mechanism that allows a class to inherit properties and methods from another class, known as its superclass. This allows developers to reuse code and avoid duplicating functionality across multiple classes.

One of the key benefits of using inheritance in TypeScript is that it allows developers to create more specific subclasses that share common functionality with their parent classes. This makes code more modular and easier to maintain, since changes made to the parent class are automatically inherited by its subclasses. It also allows for more concise and readable code, since developers can avoid duplicating code across multiple classes.

Here’s an example that illustrates the benefits of inheritance in TypeScript:

class Vehicle < constructor(public make: string, public model: string) <>start() < console.log(`$$ is starting. `); > stop() < console.log(`$$ is stopping. `); > > class Car extends Vehicle < constructor(public make: string, public model: string, public doors: number) < super(make, model); >drive() < console.log(`$$ with $ doors is driving. `); > > class Truck extends Vehicle < constructor(public make: string, public model: string, public payload: number) < super(make, model); >load() < console.log(`$$ is loading $ pounds. `); > unload() < console.log(`$$ is unloading $ pounds. `); > > const car = new Car('Honda', 'Civic', 4); car.start(); // Output: "Honda Civic is starting. " car.drive(); // Output: "Honda Civic with 4 doors is driving. " car.stop(); // Output: "Honda Civic is stopping. " const truck = new Truck('Ford', 'F-150', 5000); truck.start(); // Output: "Ford F-150 is starting. " truck.load(); // Output: "Ford F-150 is loading 5000 pounds. " truck.unload(); // Output: "Ford F-150 is unloading 5000 pounds. " truck.stop(); // Output: "Ford F-150 is stopping. "

In this example, we have a Vehicle class that has a make and model property and a start and stop method. We then define a Car subclass and a Truck subclass that both extend the Vehicle class and add additional properties and methods that are specific to cars and trucks.

When we create new instances of the Car class and the Truck class and call their start , drive , load , unload , and stop methods, it outputs the corresponding messages, showing how inheritance can be used to create more specific subclasses that share common functionality with their parent classes.

Here’s another example that illustrates the benefits of inheritance in TypeScript:

class Person < constructor(public name: string, public age: number) <>sayHello() < console.log(`Hello, my name is $and I'm $ years old.`); > > class Student extends Person < constructor(public name: string, public age: number, public major: string) < super(name, age); >study() < console.log(`I'm studying $.`); > > class Teacher extends Person < constructor(public name: string, public age: number, public subject: string) < super(name, age); >teach() < console.log(`I'm teaching $.`); > > const student = new Student('John Doe', 20, 'Computer Science'); student.sayHello(); // Output: "Hello, my name is John Doe and I'm 20 years old." student.study(); // Output: "I'm studying Computer Science." const teacher = new Teacher('Jane Smith', 35, 'Mathematics'); teacher.sayHello(); // Output: "Hello, my name is Jane Smith and I'm 35 years old." teacher.teach(); // Output: "I'm teaching Mathematics."

In this example, we have a Person class that has a name and age property and a sayHello method. We then define a Student subclass and a Teacher subclass that both extend the Person class and add additional properties and methods that are specific to students and teachers.

When we create new instances of the Student class and the Teacher class and call their sayHello , study , teach methods, it outputs the corresponding messages, showing how inheritance can be used to create more specific subclasses that share common functionality with their parent classes.

Understanding the concept of code reuse and inheritance in TypeScript is key to building scalable and maintainable applications. In the next section, we’ll explore some examples of inheritance in TypeScript using the «extends» keyword.

Implementing Interfaces

Interfaces are a key feature of TypeScript that allow developers to define a contract between different parts of a system. An interface defines a set of properties and methods that a class must implement in order to be considered valid according to that interface. This allows developers to ensure that different parts of a system work together seamlessly by adhering to a common set of rules.

One of the key benefits of using interfaces in TypeScript is that they provide a way to enforce type safety and reduce errors in code. By defining interfaces that describe the expected behavior of classes, developers can catch errors early in the development process and avoid costly mistakes down the line. Interfaces also make code more modular and easier to maintain, since they provide a clear separation of concerns and allow for more concise and readable code.

Here’s an example that illustrates the benefits of interfaces in TypeScript:

interface Animal < name: string; makeNoise: () =>void; > class Dog implements Animal < constructor(public name: string) <>makeNoise() < console.log(`$barks.`); > > class Cat implements Animal < constructor(public name: string) <>makeNoise() < console.log(`$meows.`); > > const dog = new Dog('Fido'); dog.makeNoise(); // Output: "Fido barks." const cat = new Cat('Whiskers'); cat.makeNoise(); // Output: "Whiskers meows."

In this example, we have an Animal interface that defines a set of properties and a makeNoise method. We then define a Dog class and a Cat class that both implement the Animal interface, ensuring that they both have the necessary properties and methods to be considered animals.

When we create new instances of the Dog class and the Cat class and call their makeNoise methods, it outputs the corresponding messages, showing how interfaces can be used to enforce type safety and ensure that different parts of a system work together seamlessly.

In conclusion, understanding the concepts of inheritance and interfaces in TypeScript is crucial for building scalable and maintainable applications. Inheritance allows developers to reuse code and create more specific subclasses that share common functionality with their parent classes, while interfaces provide a way to enforce type safety and ensure that different parts of a system work together seamlessly by adhering to a common set of rules.

Источник

Оцените статью