title: D3 callback function's `this` shadows object's `this`
body: <p>I have a class that's wrapping D3. I'm converting it to TypeScript and I'm getting the following two errors and can't figure out how to fix them (well actually there are multiple errors but they're all similar to this pair),</p>
  
  <pre><code>src/d3-graph.ts:295:19 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. 
  295         d3.select(this)
                        ~~~~
  
    src/d3-graph.ts:294:23
      294       .on('mouseout', function(d: any) {
                                ~~~~~~~~
      An outer value of 'this' is shadowed by this container.
  </code></pre>
  
  <p>Code (a method inside a class with line numbers added for reference),</p>
  
  <pre><code>...
  1 private _enableNodeHighlightOnHover() {
  2   this._nodes
  3     .on('mouseout', function(d: any) {
  4       d3.select(this)
  5         .style('stroke-width', '2px')
  6     })
  7 }
  ...
  </code></pre>
  
  <p>Notice on line 2, the <code>this</code> refers to the instance object of the class.</p>
  
  <p>On line 4, the <code>this</code> refers to the object D3 has bound onto the callback found provided to the <code>on</code> (line 3). Also note the use of <code>function</code> over <code>(...) =&gt; {  ... }</code> -- to allow D3 to bind the <code>this</code> to the object it needs to.</p>
  
  <p>I'm more than happy to lose the <code>this</code> usage in the callback function if I can access the D3 object I'm using in <code>d3.select(this)</code> in some other way. But I'm not sure what that way would be.</p>
  
  <p>There are other uses of this pattern that will need to be accommodated as well,</p>
  
  <pre><code>private _enableDrag() {
    const that = this
  
    this._drag = d3.drag()
    this._drag
      .on('drag', function(d: any) {
        d.x += d3.event.dx
        d.y += d3.event.dy
  
        d3.select(this)
          .attr('cx', d.x)
          .attr('cy', d.y)
  
        that._links.each(function(l: any) {
          if (l.source === d.id)
            d3.select(this)
              .attr('x1', d.x)
              .attr('y1', d.y)
          else if (l.target === d.id)
            d3.select(this)
              .attr('x2', d.x)
              .attr('y2', d.y)
        })
  
        if (that._nodeTextLabels === null)
          logger.warn(
            'enableDrag called before this._nodeTextLabels has been initialized')
        else
          that._nodeTextLabels.each(function(n: any) {
            if (n.id == d.id)
              d3.select(this)
                .attr('x', d.x + D3Graph._LABEL_FONT_SIZE / 2)
                .attr('y', d.y + 15)
          })
  
        that._nodes.each(function(n: any) {
          if (n.id == d.id)
            d3.select(this).select('circle')
              .attr('cx', d.x)
              .attr('cy', d.y)
        })
      })
  }
  </code></pre>