Tried to pass this
with type in a class method and then try to access it in 2 ways:
-
Create a new JS object and assign a value. (No Error)
{
getName: obj1.getName
} in below code -
Save it to a new variable(reference) and call it (Gives Error)
const a = obj1.getName;
in below code
What is the concept behind these two? When I have defined
this: MyClass
saying it is of typeMyClass
then it should give error for the first one as well.
typescript code
class MyClass {
x:string = "Class value";
getName(this: MyClass) {
return this.x;
}
}
// Creating class object
const obj1 = new MyClass();
console.log(obj1.getName());
// Creating JS object
const obj2 = {x: 'Object Value', getName: obj1.getName}
// Will not give error
console.log(obj2.getName());
// Will give error with below line
const a = obj1.getName;
a();
Error: The 'this' context of type 'void' is not assignable to method's 'this' of type 'MyClass'.(2684)
Ref:
- Typescript Documentation: https://www.typescriptlang.org/docs/handbook/2/classes.html#this-parameters
3
Answers
In the above code
obj2
has same signature/definition asMyClass
thats why it consider that object as an instance of classMyClass
and hence didn't give error.While in second case it has different signature and hence typescript gave error.
If we try to create obj2 with x as a number, then signature gets different and it will give error:
Example:
Error:
The 'this' context of type '{ x: number; getName: (this: MyClass) => string; }' is not assignable to method's 'this' of type 'MyClass'
Another example:
Error:
If this were just regular JS I would advise you to read more about bind, call and apply and how context can be re-used/re-created.
I think (based on my limited experience) that this time the ts error is spot on. The ‘a’ variable does not have any context of what this.x is. This is why ts is smartly giving you an error. Upon invocation, there is no way for it to determine where/what this.x is.
The error you encountered is due to a type mismatch between the expected ‘this’ context of the ‘getName’ method and the actual context provided when invoking the method through the ‘a’ variable.
In the MyClass definition, the getName method is explicitly annotated with this: MyClass, indicating that it expects to be called on an instance of MyClass. This ensures that the method can access the x property correctly.
However, when you assign obj1.getName to a and invoke it as a(), the ‘this’ context is no longer implicitly bound to obj1. Therefore, TypeScript infers the type of ‘a’ as (this: void) => string, which means it is a function expecting no context (or a context of void). Consequently, TypeScript raises an error when you invoke a() because it does not meet the expected ‘this’ context type for getName.
To fix this issue, you can explicitly bind the ‘this’ context to obj1 when assigning obj1.getName to a. Here’s an updated code snippet:
const a = obj1.getName.bind(obj1);
console.log(a()); // Output: "Class value"
By using the bind method, you ensure that the ‘this’ context inside a is bound to obj1, allowing the method to be invoked successfully without any type errors.