Home > database >  Typescript this as a function parameter/return type
Typescript this as a function parameter/return type

Time:09-05

I would like to be able to reference the type of the current object in a function's parameter/return type, such as the following:

in .d.ts:

interface Object {
    add(object: Partial<this>): this;
}

in .js:

Object.prototype.add = function(object) {
    Object.assign(this, object);
}

The intended behavior of this function is to only allow the parameter to contain properties that are already defined on the object via Partial<this>. However, in attempted use such as

document.body.style.add({
    fontSize: "12px"
});

TypeScript gives me the following error:

Argument of type '{ fontSize: string; }' is not assignable to parameter of type `Partial<Object>`.
Object literal may only specify known properties, and 'fontSize' does not exist in type 'Partial<Object>'.

I assume that this is because the this types in my .d.ts actually just refers to Object because that's the containing interface for the function instead of recognizing the CSSStyleDeclaration type that document.body.style is. How can I achieve a function like this, that uses the type of the object it's being applied to as parameters/return type? Is this possible in TypeScript?

CodePudding user response:

Disclaimer: it is considered bad practice to modify native prototypes this way. You may have some reason why it's okay to do this for your use cases, but you should probably avoid it. Anyway, let's move on.


As you noticed, the polymorphic this type doesn't really work the way you want for the native interface types like Object, String, etc.. Even known subtypes of Object will see this rendered as Object instead of the known subtype.

As a workaround you can emulate the desired behavior by making the method generic and give it a generic this parameter:

interface Object {
  add<T>(this: T, object: Partial<T>): T;
}

So now if you call add() on some object of type CSSStyleDeclaration, the type checker will infer T to be CSSStyleDeclaration, and thus expect a Partial<CSSStyleDeclaration> as its parameter. So the following works as expected:

document.body.style.add({
  fontSize: "12px"
});
// (method) Object.add<CSSStyleDeclaration>(
//   this: CSSStyleDeclaration, object: Partial<CSSStyleDeclaration>
// ): CSSStyleDeclaration

Playground link to code

  • Related