Skip to content

Fixing undefined 'this' in Javascript  #24636

Closed
@olmobrutall

Description

@olmobrutall

Search Terms

undefined this

Suggestion

With structural typing, generics, union, conditional types, etc. Typescript has reached the heaven of sofistication, but one (the?) elephant in the room is the annoying behaviour of 'this' in typescript.

https://twitter.com/bendhalpern/status/578925947245633536

I know that TS has a way to define the type of the this parameter, but does nothing in checking whether this is going to be bound or not by the time the function runs.

The problem

class MyComponent : React.Commponent {

     constructor(){
          this.handleCickBoundMethod = this.handleCickBoundMethod.bind(this);
     }

     handleClickLambda: ()=>{  
         this.forceUpdate(); 
     }
     handleClickMethod(){
         this.forceUpdate();
     }
     handleClickBoundMethod(){
         this.forceUpdate();
     }

      render(){
           return (
            <div>
               <button onClick={this.handleLambda} /> //OK
               <button onClick={this.handleMethod} /> //Error!
               <button onClick={()=>this.handleMethod()} /> //OK
               <button onClick={this.handleClickBountMethod} /> //OK
            </div>
           );
      }
}

The solution

Every class method (not lambda) that uses this (directly or in a inner lambda) is internally marked in the compiler as 'unbound-this'.

Methods marked with unbout this can be only called as an instance method, and can not be assigned to variables or passed as parameters.

This mark can be reverted with some cast or using bind.

<button onClick={this.handleMethod} />//TS Error: this will be undefined. 
<button onClick={this.handleMethod as (()=>void)}> //Avoid TS error at your own risk. 

I think lambda capturing is considered:

<button onClick={()=>this.handleMethod()} />

In this case, the lamda is already capturing this, and we are just calling the method not passing it, so should be ok.

Limitations

When this is used in normal functions outside of classes, (where you need the explicit this parameter in strict) this tracking will not help (for now).

function joinComma(this any[]){
    return this.join(", ");
}

Array.prototype.joinComma = joinComma; 

[1, 2, 3].joinComma(); //Ok
joinComma([1, 2, 3]); //Runtime error, still not solved in TS. 

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
    It will add aditional errors, but that's the 'name of the game'.
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions