Curious to understand the similarities and differences between a Man and a Child.
class Individual {
name: string;
age: number;
}
class Child extends Individual {}
class Man implements Individual {}
Curious to understand the similarities and differences between a Man and a Child.
class Individual {
name: string;
age: number;
}
class Child extends Individual {}
class Man implements Individual {}
extends
signifies:The new class acts as a derivative. It inherits the attributes and methods of its parent while being able to override or introduce new ones, but it inherently includes the parent's features.
implements
denotes:The new class assumes a similar "shape" to another, although it is not a direct descendant. This allows it to substitute for the equivalent of the specified type, even if it has a different lineage from the original type.
In the world of OOP (such as C# or Java), we utilize
extends
for benefiting from inheritance.
... In object-oriented languages with classes, inheritance is a process where one entity acquires all the attributes and behaviors of the parental entity. Inheritance allows programmers to: construct classes based on existing classes ...
implements
is more aligned with polymorphism.
... polymorphism refers to presenting a single interface that can apply to entities of diverse kinds...
Therefore, our class Man
could have a distinct inheritance chain:
class Man extends Human ...
but by specifying that Man
can masquerade as the Person
category:
class Man extends Human
implements Person ...
...we permit using it in any scenario requiring a Person
. The criteria are simply fulfilling Person
's "interface" (i.e., implementing all its public elements).
Javascript showcases an appealing aspect (among many) like built-in support for duck typing.
"If it walks like a duck and it quacks like a duck, then it must be a duck."
Hence, in Javascript, if two distinct objects possess a common method (e.g., render()
), they can be utilized interchangeably in functions expecting it:
function(engine){
engine.render() // any type with render() can fit
}
To maintain this feature in Typescript while enhancing type safety, we incorporate similar concepts with added typed assistance. This plays a pivotal role where applicable.
In OOP dialects like C#
, achieving this would be unattainable.
Interfaces Extending Classes
When an interface type extends a class type, it inherits the properties of the class without inheriting their implementations. Essentially, it mimics declaring all members of the class sans providing an actual implementation. Interfaces even inherit private and protected members from a base class. Consequently, creating an interface that extends a class holding private or protected elements restricts its implementation solely to said class or its descendants.
This approach becomes beneficial within extensive inheritance hierarchies when enforcing compatibility exclusively with subclasses embodying specific qualities. Such subclasses need not share any intrinsic relation beyond their ancestral connection. For instance:
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } } class TextBox extends Control { select() { } } // Error: Property 'state' is missing in type 'Image'. class Image implements SelectableControl { private state: any; select() { } } class Location { }
Hence, while
extends
ensures complete inheritance from the parentimplements
almost emulates implementing an interface in this context. A child entity can imitate its parent... though devoid of automatic implementation transfer.When dealing with classes and interfaces in TypeScript (as well as other object-oriented languages), it's important to understand their distinct roles.
An interface serves as a blueprint, outlining what methods and properties a type must have without providing any actual implementation. It essentially defines a "contract" that implementing instances must adhere to.
For instance:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
In this example, any object implementing the Point
interface must include two number-type members (x
and y
) and a method named distance
, which takes another Point
instance as a parameter and returns a number.
The real meat of the functionality lies in classes, which are responsible for implementing the details specified by interfaces:
class PointImplementation implements Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public distance(other: Point): number {
return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
}
}
As illustrated in the code snippet above, classes provide the actual implementation based on the requirements laid out by interfaces.
It's worth noting that when extending or implementing classes/interfaces, there are subtle distinctions to keep in mind:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
In the case of trying to implement the Person
interface with the Man
class, you may encounter errors if the necessary properties are not defined, highlighting the fact that interfaces do not contain implementations.
To rectify such errors, make sure to explicitly define all required properties within the implementing class:
class NoErrorMan implements Person {
name: string;
age: number;
}
Ultimately, the key takeaway is that when working with classes and interfaces, it's essential to grasp the distinction between extending a class (inheriting its properties and methods) and implementing an interface (adhering to a set of rules without inheriting any concrete implementations).
extends
: When a child class inherits all properties and methods from the parent class it extends
.implements
: The class using the implements
keyword must implement all properties and methods declared in the interface it implements
.Simplified explanation:
extends
: Automatically acquires methods/properties from the parent class, eliminating the need for manual implementation.implements
: Acts as a contractual obligation for the class to adhere to, ensuring implementation of specified methods/properties.class Person {
name: string;
age: number;
walk(): void {
console.log('Walking (person Class)')
}
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Child extends Person { }
// Man is required to implement all properties
// and methods of the Person class
class Man implements Person {
name: string;
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('Walking (man class)')
}
}
(new Child('Mike', 12)).walk();
// Output: Walking(person Class)
(new Man('Tom', 12)).walk();
// Output: Walking(man class)
In the given example, we see that the Child class inherits everything from Person, while the Man class must implement all aspects of Person itself.
If something was removed from the Man class, like the walk method, a compile time error would occur:
'Man' does not correctly implement 'Person'. Should you perhaps extend 'Person' to inherit its members as a subclass? Property 'walk' is missing in type 'Man' but is required in type 'Person'.(2720)
What an insightful response from @nitzan-tomer! I found it extremely helpful and decided to expand on his demonstration a bit by incorporating:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
I then explored how these elements behave within functions that expect an IPoint
type.
From this experience, I've adopted a rule of thumb: when working with classes and methods that require generic types, utilize interfaces as the expected types. Additionally, ensure that the parent or base-class utilizes that interface so that all subclasses implementing the interface can be used effectively in those scenarios.
You can access the expanded demo here.
In simple terms:
extends
allows us to inherit all the properties and methods from the parent class.implements
requires us to provide implementations for all the properties and methods specified in the interface.extends
focuses on inheritance while implements
concentrates on restrictions for interfaces or classes.
Utilizing interfaces in programming serves to decrease the connection between classes by establishing a set of rules or common communication system that dictates how various classes can engage with each other. This approach fosters a more flexible and easily maintainable codebase, as it encourages loose connections and facilitates future expansions (Adopting an interface-driven design). Through the implementation of interfaces rather than inheritance, the interdependencies among classes are minimized, resulting in decreased code entanglement. This separation improves the ability to reuse code, conduct thorough testing, and enhance the overall adaptability of the system.
extends
": The keyword is utilized when a class
or interface
"extends" another class
or interface> of the same type within its hierarchy.</li>
<li>"<code>implements
" : This keyword is used specifically when a class
implements an interface
.Recently, I delved into the realm of typescript and decided to explore TypeORM for backend development. My current project involves building a CRUD API using typeORM and postgreSQL. After configuring everything initially, I ran the application only to rea ...
Working on a personal project and came across a library called merge-graphql-schemas. Since the module lacks its own typings, I created a file at src/types/merge-graphql-schemas.d.ts In merge-graphql-schemas.d.ts, I added: declare module "merge-graphql-s ...
Currently, I am working with a table that dynamically creates rows containing details of uploaded files. Each row includes a dropdown menu for selecting the file type. The issue I am encountering is with the dynamically generated dropdown menus. If I sele ...
How can I filter a list of JSON objects (Products) by the 'category' variable using checkboxes? An example product object is shown below: { 'bikeId': 6, 'bikeName': 'Kids blue bike', 'bikeCode': ...
How can I create an array that is initialized with values depending on a specific type? type Animals = 'monkey' | 'elephant' | 'lion'; const animalsArray: Array<Animals> = []; // ['monkey', 'elephant&apos ...
This project is a combination of Next.js with TypeScript, tRPC, MySQL using Prisma, and Pinecone for vector DB. Uploadthing is integrated for PDF uploads. Despite successful upload, there is an issue when trying to open the PDF on the website, resulting in ...
Currently, I am working on an application utilizing NestJS and TypeORM. My main objective is to handle TypeORM errors by using exception filters. However, I have run into a roadblock as I am facing this particular error: (node:345) UnhandledPromiseReject ...
While using Sentry to catch errors in my React app, I discovered that it ignores errors with 502 and 504 HTTP codes as well as some React errors. I am unsure why this is happening and would like to modify this behavior. Below is the initialization functio ...
I have been facing an issue while trying to set up my reactive form with an observable that I subscribed to. Within the form class template, I used the ngOnInit lifecycle hook to fetch the desired object, which is the product. The first code snippet repre ...
import React, { useState } from "react"; import "./index.css"; import { TimePicker } from "antd"; import type { Dayjs } from "dayjs"; const format = "HH:mm"; const Clock: React.FC = () =& ...
I'm attempting to append multiple header values. This is what I'm currently doing: options.headers.append('Content-Type', 'application/json'); options.headers.append('X-Requested-By', 'api-client'); ... ...
When submitting the form, an error occurs when trying to repopulate the data back to the form: ERROR TypeError: Cannot read property 'id' of undefined This is in reference to the code snippet: <select [(ngModel)]="insurer.group.id" name="grou ...
Received data from API: const abc = [ { date: '2023-12-8', value: 'mop' },{ date: '2023-10-8', value: 'qrs' } ] How can we create a date range using two input fields when the dates are in string forma ...
While working with React, I encountered a peculiar issue. I have an array variable named messages defined using the useState hook. Additionally, there is a component on the page that listens for events on a websocket but doesn't contain any DOM elemen ...
Here is the code snippet I am working with: import * as Phaser from 'phaser'; new Phaser.Game({ width:300, height:300, scale: { mode: Phaser.Scale.FIT, }, type: Phaser.AUTO, scene: { create() {} }, }); Upon compi ...
Currently working with the following versions: "react-native": "0.59.10" "react-native-reanimated": "^1.3.0" using TypeScript Encountering a type error related to transform properties. const Example = () => { const { translationX, gestureHandler } = ...
I'm curious to know what sets apart these two approaches when declaring the status property. I understand that the second version maintains type safety, but how exactly does it achieve this? export type OwnProps = { id: number; name: string; sta ...
Would it be possible to access this.$refs.label? I am using the package vue-property-decorator. Below is the content of the component: <template> <div> <label ref="label">asd</label> </div> </template> <scr ...
The issue is straightforward - I have a component that retrieves the last searched items saved in sessionStorage as an array of ListItem objects: export class SearchlistComponent { results = JSON.parse(<string>sessionStorage.getItem("lastSear ...
I followed the instructions to add the AgmMarkerSpiderModule from the official package documentation. However, when I compile, I encountered the following error message: /directives/marker-spider.ts:14:24 - error TS2307: Cannot find module '@agm/core/ ...