The impact of redefining TypeScript constructor parameter properties when inheriting classes

Exploring the inner workings of TypeScript from a more theoretical perspective.

Referencing this particular discussion and drawing from personal experiences, it appears that there are two distinct methods for handling constructor parameter properties when extending a class.

Approach 1: Passing existing fields

class Base {
    constructor(public field: string) {}
}

class Derived extends Base {
    constructor(field: string) {
        super(field);
    }
}

Approach 2: Redeclaring existing fields

class Base {
    constructor(public field: string) {}
}

class Derived extends Base {
    constructor(public field: string) {
        super(field);
    }
}

According to the insights provided in the aforementioned question and answer, there are constraints on how the field can be redeclared, which I have come to understand.

Prompting the following inquiries:

  • Does the second method result in defining two separate fields within the class, with one overshadowed by the other? Will this.field and super.field reference different attributes of the class?
  • In a similar vein to the previous question, does the second approach yield contrasting outcomes when dealing with methods specified in the Base and Derived classes?

Fundamentally, the inquiry stands as follows: Do these approaches exhibit identical functionality, or do they diverge in certain exceptional scenarios?

Based on personal encounters, both methods seem to achieve equivalent results.

I lean towards the first approach personally, as it gives me a sense of security knowing that "nothing can go awry," without any hidden pitfalls. However, delving deeper into this subject would aid me in avoiding basing my programming decisions solely on vague instincts.

Your input is greatly appreciated. Thank you.

Answer №1

Is it possible for a class in the second method to have two fields, where one field shadows the other? Will accessing this.field and super.field return different values within the class?

No, in JavaScript (and by extension TypeScript), an object can only contain one property with a specific name.¹ (super.x() works with prototype methods since they belong to the prototypes of the Base and Derived classes, not the object [instance].)

Similarly to the last inquiry, does the behavior differ when it comes to methods defined in the Base and Derived classes using the second approach?

I'm unclear on your question, but I hope the explanation that follows will address it.

The redeclaration version poses issues, and it's advisable to avoid it. Let's examine the resulting JavaScript code (when targeting ES2015+):

class Base {
    constructor(field) {
        this.field = field;
    }
}
class Derived extends Base {
    constructor(field) {
        super(field);
        this.field = field;
    }
}

Note how Derived passes field to Base, then overwrites what Base had set with its own statement this.field = field.

In the case of the specific definition of Base provided, this is likely fine (albeit redundant) as Base simply assigns its field parameter, which Derived also does later. However, if the author of Base were to make changes:

class Base {
    public field: string;
    constructor(field: string) {
        this.field = field.trim(); // Or something similar
    }
}

Now, Derived would disrupt things since the work done by Base is discarded and replaced by the this.field = field statement in Derived.


¹ This differs in some languages. For example, in Java, it's feasible for an object to have multiple properties with the same name introduced by different classes in its hierarchy. The choice of which one to use depends on where the employing method is situated. Yet in JavaScript or TypeScript, this is not applicable.

Answer №2

Upon examining the compiler output, it becomes evident that when redeclaring the field in the derived class, an additional assignment is made after invoking the constructor of the base class. Any modification to the passed value in the super constructor will be overwritten by this assignment.

class Base {
    constructor(public field: string) { }
}

class DerivedOne extends Base {
    constructor(field: string) {
        super(field);
    }
}

class DerivedTwo extends Base {
    constructor(public field: string) {
        super(field)
    }
}

Result

var __extends = ...;

var Base = /** @class */ (function () {
    function Base(field) {
        this.field = field;
    }
    return Base;
}());

var DerivedOne = /** @class */ (function (_super) {
    __extends(DerivedOne, _super);
    function DerivedOne(field) {
        return _super.call(this, field) || this;
    }
    return DerivedOne;
}(Base));

var DerivedTwo = /** @class */ (function (_super) {
    __extends(DerivedTwo, _super);
    function DerivedTwo(field) {
        var _this = _super.call(this, field) || this;
        _this.field = field;   // The value is reassigned here
        return _this;
    }
    return DerivedTwo;
}(Base));

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

Should I opt for ionic2 for my production needs?

Currently, I am using Ionic 1 and AngularJS 1 for our applications. We are considering transitioning to Ionic 2 for our new applications. Is this the right decision? I have a few questions: AngularJS 1 and Angular 2 are different, but how does Ionic ...

Ways to obtain the file path of the compiled worker.js loaded from the worker loader, along with its hash

Currently, I am working on a TypeScript React application that utilizes Babel and Webpack for compilation. I have implemented a rule to load my worker with the following configuration: config.module.rules.unshift({ test: /gif\.worker\.js$/, ...

A guide on managing Ngb Bootstrap carousel slide with a button in Angular

I encountered a situation like this: I need to implement a Ngb Bootstrap carousel with buttons for Previous and Next to control the slide images. Clicking on the Previous button should display the previous slide image, and clicking on the Next button shou ...

Encountering Angular error when trying to assign an undefined array to another array while using mock data

Attempting to conduct unit testing on a component involving the retrieval of 'Groups' data through a data resolver class. Below is the corresponding code: export class GroupsComponent implements OnInit, OnDestroy { group: IGroup; groups: IGro ...

Is there a way to attach a Blob/File array to formData in typescript?

If I didn't have an ARRAY of files, this method would work perfectly. However, it needs to be in the form of an Array. let file1 = new File([""], "filename"); let file2 = new File([""], "filename"); let fi ...

Tips for concealing tick labels in d3 using TypeScript

When trying to hide tick labels by passing an empty string to the .tickFormat("") method, I encountered an issue with Typescript. The error message received was as follows: TS2769: No overload matches this call. Overload 1 of 3, '(format: null): Axi ...

The response of the Typescript Subscription function

I'm struggling with retrieving the subscribe array in NG2. Being new to typescript, I find it difficult to understand how to pass variables between functions and constructors. This is what my code currently looks like: export class RosterPage exten ...

Exploring Manipulation of M:N Associations in Sequelize

I have set up a sequelize schema using postgre DB export const Commune = sq.define("commune",{ codeCommune: { type: DataTypes.STRING(5), allowNull: false, primaryKey: true }, libelleCommune: { type: ...

How can you utilize a JavaScript library that provides global variables in Typescript?

I am closely adhering to the guidance provided in the official manual for declaration. Global library // example.js example = 20; Declaration file // example.d.ts declare const let example: number; Implementing the declaration file and library // ind ...

What is the best way to implement ES2023 functionalities in TypeScript?

I'm facing an issue while trying to utilize the ES2023 toReversed() method in TypeScript within my Next.js project. When building, I encounter the following error: Type error: Property 'toReversed' does not exist on type 'Job[]'. ...

Limiting the parameter type in Node.js and TypeScript functions

Currently working on a Node.js project utilizing TypeScript. I'm attempting to limit the argument type of a function to a specific base class. As a newcomer to both Node and TypeScript with a background in C#, I may not fully grasp some of the langua ...

What are the steps for designing personalized syncfusion grid-columns while still preserving the built-in search functionality of syncfusion?

Looking to transform the data coming from the backend, specifically mapping a user's status which is represented as a number to its corresponding string value. Considered using typescript for this mapping task, but it interferes with syncfusion' ...

What is causing my function to execute twice in all of my components?

One issue I am facing is that I have created three different components with routing. However, when I open these components, they seem to loop twice every time. What could be causing this behavior and how can I resolve it? For instance, in one of the comp ...

Contrast the different characteristics of string dynamic arrays in Angular 6

I am working with two arrays of strings. One array is a dynamic list of checkboxes and the other is the source to check if the item exists in the first array. I need to implement this dynamically using Angular 6, can you help me with this? Currently, the ...

Employing Class Categories in Static Procedures

I am currently working on developing a foundational Model that will serve as the base for a specific model class, which will have an interface detailing its attributes. Within the base Model class, I am aiming to incorporate a static factory() function th ...

Combining 2 lists in Angular Firebase: A Simple Guide

I have been searching for a solution for the past 2 hours, but unfortunately haven't found one yet. Although I have experience working with both SQL and NoSQL databases, this particular issue is new to me. My problem is quite straightforward: I have t ...

Tips for effectively hydrating Redux state in Next.js upon page refresh?

I'm experiencing an issue with hydrating user data from local storage upon app reload or page refresh. My project utilizes NextJS for the frontend, and for managing state across the application I rely on redux-toolkit and next-redux-wrapper. Upon us ...

Express string declaration in a single TypeScript line

const restrictString = (str: string): string => str.match(/[ab]/g)?.join('') || '' Is there a way to restrict a string to only contain the characters 'a' and 'b' in a one-liner function? I am aware that this can ...

Leveraging the typeof Operator within a Class

How can we utilize typeof in order to specify the type of a class property? Take a look at both examples below, where example A works but example B does not. A) Works outside class const data: {age:number, name:string} = {age:10, name:'John'}; c ...

Having trouble viewing the value of request headers in Firebase?

Here is my code snippet: var headers = new Headers(); headers.append("bunny", "test"); headers.append("rabbit", "jump"); fetch("blahurl.com/someservice", {headers:headers}) When it comes to handling the request on Firebase: export const listener = funct ...