What is the reason for instances being compatible even if their class constructors do not match?

Why are the constructors in the example below not compatible, but their instances are?

class Individual {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

class Worker {
  name: string;
  age: number;
  salary: number;
  constructor(name: string, age: number, salary: number) {
    this.name = name;
    this.age = age;
    this.salary = salary;
  }
}

const indCtor: typeof Individual = Worker; // an error is thrown as constructors are incompatible
const individual: Individual = new Worker("", 0, 0); // however, the instances can still be compatible - how does this work?

Answer №1

Take a look at microsoft/TypeScript#3841 for a definitive response to this inquiry. The constructor property of class instances lacks strong typing in TypeScript. It is simply assigned the type Function, allowing types like Employee and Person to be interchanged without conflict.


However, why isn't p.constructor more strongly typed? Refer to this comment in microsoft/TypeScript#3841 for explanation.

In TypeScript, it is highly preferable for extended classes to also extend their instances. This allows class Foo extends Bar { ⋯ } to imply that Foo extends Bar, ensuring that class hierarchies align with type hierarchies. Without this alignment, code like const bar: Bar = new Foo() would throw errors, causing major disruption to existing codebases.

JavaScript permits subclass constructors to differ from those of their superclasses, which is necessary given some JavaScript inheritance patterns. Thus, scenarios like the following are allowed:

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

class Employee extends Person {
  salary: number;
  constructor(name: string, age: number, salary: number) {
    super(name, age);
    this.salary = salary;
  }
}

const pCtor: typeof Person = Employee; // error, incompatible constructors
const p: Person = new Employee("", 0, 0); // no error, compatible instances

This means that p.constructor cannot be of type typeof Person without disrupting the mentioned code. While perhaps p.constructor could possess additional specificity beyond Function, current functionalities do not reflect this. Nonetheless, this does not impact the provided example scenario.


It's crucial to note that from a type system perspective, your code example mirrors this one identically. Despite differences in the resulting behavior of p instanceof Person, the structural compatibility remains unchanged. No extends clause is necessary for types to align. Even if an Employee class looks like this:

class Employee {
  name: string;
  age: number;
  salary: number;
  constructor(name: string, age: number, salary: number) {
    this.name = name;
    this.age = age;
    this.salary = salary;
  }
}

there won't be any alterations in TypeScript's behavior. An Employee's constructor property maintains a type of Function, resulting in every Employee being structurally compatible with Person.

Visit Playground link to view the code

Answer №2

When Type A is compatible with Type B, it means that an instance of Type A can function as an instance of Type B, supporting all necessary operations and methods.

An Employee can perform all operations on a Person, making it suitable to be assigned to a Person variable.

Incompatibility in constructors does not affect this relationship, since constructors are not operations performed on instances of the class. Constructors are not called on objects of type 'Person' or 'Employee'.

Furthermore, even without the constructor issue, the types are not identical: Employee instances cannot be assigned to variables of type Person, as Employee includes a salary field while Person does not. Attempting to use a Person where an Employee is expected may result in a TypeScript error for safety reasons, but using an Employee as a Person does not pose such risks.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the correct way to wrap an http.get in TypeScript?

My understanding of Typescript is limited, so I have a basic question related to my web application's frontend. In most http get-requests, I need to include two parameters. To simplify this process, I created a simple wrapper for HttpClient (from "ang ...

Ways to change a value into int8, int16, int32, uint8, uint16, or uint32

In TypeScript, the number variable is floating point by default. However, there are situations where it's necessary to restrict the variable to a specific size or type similar to other programming languages. For instance, types like int8, int16, int32 ...

What is the method to transfer the outcome of a GET request into a POST request?

My task involves sending a GET request to retrieve information from . When the request is made, it generates a random image and returns a JSON object that includes details such as "fileSizeBytes" and "url". My goal is to extract the "url" value and then ...

Tips for implementing a real-time search feature in Angular

I require assistance. I am attempting to perform a live search using the following code: when text is entered into an input, I want my targetListOptions array, which is used in a select dropdown, to update accordingly. The code runs without errors, but not ...

What are the steps to customize the collapse and expand icons?

Having trouble changing the icon up and down when collapsing and expanding with the code below. <div class="attach-link"> <a href="javascript:void(0);" *ngIf="fileData.fileDataType.canAttach && !isFinancialEntity" (click) ...

Trigger event when ngModel changes

Currently, I am trying to perform a test on a select element... <select [ngModel]="selectedRouters" name="routerName" class="form-control" id="routersSelect" size="12" (ngModelChange)="selectRouters($event)" multiple> <option [value]="route ...

Angular 2: Issue with data table not updating after item deletion

I need assistance with updating a data table after deleting an item. The database is updated correctly when I delete an item, but the table does not automatically refresh to reflect the changes. managenews.component.ts import { Component, OnInit } from ...

Issue with PassportJS and Express 4 failing to properly store cookies/session data

I have a situation with my Express 4 app using Passport 0.3.2. I've set up a passport-local strategy, and it's successfully retrieving the user information when the /session endpoint is provided with a username and password. The issue arises whe ...

Checking to see if a string meets the criteria of being a valid ARGB value

How do I verify that a string represents a valid ARGB value, such as #ffffffff for ARGB 255,255,255,255? Is there a way to validate this using TypeScript and C#? ...

Issue with IE11 compatibility in Angular2 (AngularQuickStart version 2.4.0) due to syntax error

Encountering an error in the browser console when attempting to run my Angular2 app on IE11. The error "Недопустимый знак" translates to unacceptable symbol. https://i.stack.imgur.com/0mHBC.png Here is a snippet of my index.html: <!DO ...

Top Recommendations: Comparing Standalone Components and Modules in Angular Version 14

I'm in need of some clarification on the most effective practices when it comes to utilizing standalone components and modules within Angular 14. With the introduction of standalone components as a new concept in Angular, I am seeking factual guidance ...

Unleashing the power of Typescript enums in conjunction with external modules through browserify

Previously, I utilized TypeScript internal modules and included numerous script tags to initialize my app. Now, I am in the process of transitioning the project to utilize external modules (using browserify), but I have hit a roadblock when it comes to con ...

Guide to implementing ES2022 modules within an extension

After making changes in my extension code to test various module types, I decided to modify my tsconfig.json file as follows: { "compilerOptions": { "declaration": true, "module": "ES2022", ...

Encountering issues with utilizing global variables in Ionic 3

Using Ionic 3, I created a class for global variables but encountered an error Uncaught (in promise): Error: No provider for Globals! Error: No provider for Globals! at injectionError (http://localhost:8100/build/vendor.js:1590:86) at noProviderError Th ...

Sidenav Angular Material cdkScrollable is an effective tool for creating scrollable

In Angular Material CDK, there is a special Directive called CdkScrollable that allows you to monitor ScrollEvents within a specific container. I am currently attempting to retrieve the CdkScrollable associated with the default MatSidenavContent. Unfor ...

Error TS2322 occurs during compilation in Typescript when using ng.IPromise

Having some issues while using Angular 1.x with Typescript. Here is the code causing trouble: get(id): ng.IPromise<Server.MyItem> { return this.$http.get(`${this.baseAddress}/${id}`).then(d => d.data); } After compiling with tsc, I am encoun ...

What is the best way to implement a dynamic back button in Next.js?

Being familiar with creating a standard back button, I am now eager to craft one that directs the user back by one step in the URL rather than returning to the previous page. This way, I can utilize the button in various locations without needing to alter ...

The Angular route successfully navigated to the page, but the HTML content was not

Whenever I select the Home option in the navigation bar, it takes me to the home URL but doesn't display the HTML content. Below is my app.routing.module.ts code: import { Component, NgModule } from '@angular/core'; import { RouterModule, Ro ...

Struggling to track down the issue in my ts-node express project (Breakpoint being ignored due to generated code not being located)

For my current project, I decided to use the express-typescript-starter. However, when I attempted to debug using breakpoints in VS Code, I encountered an issue where it displayed a message saying "Breakpoint ignored because generated code not found (sourc ...

implement a solution in Ionic 4 Angular 6 that triggers a function only when all the observables in a loop have

In my code, I have a function named getDevices(). This function is responsible for fetching an array of devices. After getting this array, the code iterates through each device and calls another function called updateToServer(). The purpose of updateToServ ...