Troubleshooting: Resolving the error message 'Unable to assign to Partial<this>' within a subclass method

If I call the base class's update method using a subclass instance, it functions as expected. However, I encounter an error when attempting to do so within a subclass method:

Argument of type '{ prop: number; }' is not compatible with parameter of type 'Partial<this>'.

class Base {
    update(modifier: Partial<this>) {
        Object.keys(modifier).forEach(key => {
            this[key] = modifier[key];
        });
    }
}

class Sub extends Base {
    prop;

    job() {
        // Error: Argument of type '{ prop: number; }' is not compatible 
        // with parameter of type 'Partial<this>'.ts(2345)
        this.update({ prop: 1 });
    }
}

new Sub().update({ prop: 1 }); // but it works here!

Live on the TypeScript playground.

How can I resolve this issue?

Answer №1

When it comes to polymorphic behavior in TypeScript, the use of this is not as straightforward as it may seem. In reality, this serves as a type parameter for your class, albeit a hidden one managed by the compiler. Since this is essentially a type parameter with a constraint that extends the current class (similar to

class Base<This extends Base> {}
), its full definition remains unknown within the class.

Various questions arise regarding why assigning a value to a variable with a generic type parameter or working with conditional/mapped types alongside type parameters can be challenging. An example that highlights this issue is:

function partial<T extends { prop: number }>(): Partial<T> {
    return { prop: 1 }
}

The underlying reason behind these challenges lies in the fact that we only have knowledge of the minimal interface that T must adhere to, rather than the complete structure of T. Consider the following scenario:

function getObj<T extends { prop: { name: string } }>(): Partial<T> {
    return { prop: { name: "" } }// still an error
}
var r = getObj<{ prop: { name: string, lastName: string}}>();
r.prop!.lastName // r should have last name, where is my lastName ?!

In this case, while the constraint on prop in

T</code mandates the presence of <code>name
, additional properties like
lastName</code are allowed, leading to potential discrepancies when dealing with concrete values and type parameters.</p>

<p>This same reasoning applies to polymorphic <code>this
, where due to its incomplete nature as a type parameter, direct assignment of object literals becomes problematic since the final shape of this remains ambiguous.

Consider a parallel example:

class Base {
    update(modifier: Partial<this>) {
        Object.keys(modifier).forEach(key => {
            this[key] = modifier[key];
        });
    }
}

class Sub extends Base {
    prop! :{
        name: string
    };

    job() {
        this.update({ prop: { name: string } }); // not valid for any class, example below
    }
}

class Sub2 extends Sub {
    prop! : {
        name: string
        lastName: string
    };
}

To address such issues, using a type assertion provides a workaround at the cost of compromising type safety, or incorporating a second type parameter representing the class properties restricts extending classes to a single level for adding new properties.

class Base<TProps> {
    update(modifier: Partial<TProps>) {
        Object.assign(this, modifier);
    }
}

class Sub extends Base<Sub> {
    prop: number;

    job() {
        this.update({ prop: 1 });
    }
}

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

Is there a way to define type information for a global variable when utilizing dynamic import within a function?

Here is a simplified version of my server code: server.ts import google from "googleapis"; const androidPublisher = google.androidpublisher("v3"); app.use('something', function(req, res, n){ ... }) ...(only one of the dozens of other meth ...

How to Retrieve a Symbol in TypeScript

In the code snippet below, there is a function named factory that returns a Symbol of type Bob. However, TypeScript appears to forget the type of the return value immediately, leading to an error when trying to assign the return value to variable test one ...

Angular 8: Implementing functionality for the Parent Component to detect when the User clicks outside of the Child Component Textbox

I am working on a scenario where I have a Parent Component and a Child Component containing a Formbuilder and a ZipCode textbox. Is there a way to notify the Parent Component when the user clicks out of the Child Component Textbox? I need to trigger some ...

Unsteady movement of Three JS OrbitControls during rotation

Currently, I am working on a scene with three.js and using orbit controls to rotate the camera around the scene. Occasionally, while rotating, the camera starts moving erratically before calming down and rotating smoothly again. I have read about orbit co ...

Next.js Version 13 - Unable to find solution for 'supports-color' conflict

Currently in the midst of developing a Next.js 13 app (with TypeScript) and utilizing the Sendgrid npm package. An ongoing issue keeps popping up: Module not found: Can't resolve 'supports-color' in '.../node_modules/debug/src' ...

Angular2 error: "missing exported member 'bootstrap'"

Upon opening my Atom editor, I encountered the following message: The issue of 'Module '"C:/express4/node_modules/@angular/platform-browser-dynamic/index"' not exporting member 'bootstrap' raised at line 2 col 10 This warning a ...

Using Angular 2 with the firebase-admin sdk

Whenever I attempt to integrate the firebase-admin SDK into my Angular2 project, an error occurs: ERROR in ./~/firebase-admin/lib/auth/token-generator.js Module not found: Error: Can't resolve 'jsonwebtoken' in '/home/koucky/git_projec ...

In fact, retrieve the file from an S3 bucket and save it to your local

I've been attempting to retrieve an s3 file from my bucket using this function: async Export() { const myKey = '...key...' const mySecret = '...secret...' AWS.config.update( { accessKeyId: myKey, secretAcces ...

Arranging Alphanumeric Characters in Angular in Ascending Order

I am trying to sort a list of characters first, followed by alphanumeric values. Here is what I have: [Austria , Germany , 123aed , 234eds] This is my current sorting attempt: obj.sort((a,b) => { if ( (isNaN(a.text) && isNaN(b.text)) || ...

Using TypeORM: Implementing a @JoinTable with three columns

Seeking assistance with TypeORM and the @JoinTable and @RelationId Decorators. Any help answering my question, providing a hint, or ideally solving my issue would be greatly appreciated. I am utilizing NestJS with TypeORM to create a private API for shari ...

Conditional Rendering with Next.js for Smaller Displays

I've implemented a custom hook to dynamically render different elements on the webpage depending on the screen size. However, I've noticed that there is a slight delay during rendering due to the useEffect hook. The conditionally rendered element ...

Optimizing row performance for Angular grids in the Chrome browser

When creating a component that includes a table with numerous rows, everything works well with small amounts of data. However, once the item count reaches 2000 or more, it starts lagging. Scrolling and animations become sluggish. Even after trying to impl ...

How can I implement a recursive nested template call in Angular 2?

Hopefully the title isn't too misleading, but here's my dilemma: I am in the process of building an Angular 2 app and utilizing nested templates in multiple instances. The problem I am facing involves "widgets" within my app that can contain oth ...

Is the utilization of the React context API in NextJS 13 responsible for triggering a complete app re-render on the client side

When working with NextJS 13, I've learned that providers like those utilized in the React context API can only be displayed in client components. It's also been made clear to me that components within a client component are considered part of the ...

Pause and anticipate the occurrence of AdMob's complimentary video reward event within a defined function in Ionic/Typescript

In my ionic app, I have a function that determines if the user has watched a reward video to access another function: let canUseThisFunction = await this.someService.canUseFunction(); if(canUseThisFunction){ console.log("can use"); } else { cons ...

Creating a sidebar in Jupyter Lab for enhanced development features

Hi there! Recently, I've been working on putting together a custom sidebar. During my research, I stumbled upon the code snippet below which supposedly helps in creating a simple sidebar. Unfortunately, I am facing some issues with it and would greatl ...

Is it possible for React props to include bespoke classes?

In our code, we have a TypeScript class that handles a variety of parameters including type, default/min/max values, and descriptions. This class is utilized in multiple parts of our application. As we switch to using React for our GUI development, one of ...

What is the recommended data type for the component prop of a Vuelidate field?

I'm currently working on a view that requires validation for certain fields. My main challenge is figuring out how to pass a prop to an InputValidationWrapper Component using something like v$.[keyField], but I'm unsure about the type to set for ...

Leveraging Material UI and TypeScript for Effective Styling: Maximizing the Use of !

Currently, I am in the process of developing a React application and incorporating Material UI for my components. One query that has arisen is regarding how to apply an !important property to a style. My attempt at achieving this looked like: <Paper cl ...

Initializing variables in Angular2 templates

I am facing an issue where, upon running the application, the console displays all the logs from the ngOnInit function, but the actual view only shows a skeleton without the component variables and text from l18n. It seems like the ngOnInit is not working ...