Detect if click was inside react component or not in typescript

javascript, typescript

Solution

I found a similar discussion in the typescript issue queue which says in this case a type assertion is probably unavoidable:

Basically EventTarget is the most general type, of which Element is a subtype, and HTMLElement is a subtype of that. If you get back a thing from the DOM, we generally have no idea which it is, and you should add a type assertion to "add in" the specific external knowledge that you have about the structure of your particular DOM layout.

It's possible, for example, that the .target of an event is not an Element (you can add event listeners to XMLHttpRequest, for example, and XMLHttpRequest does not have a getBoundingClientRect method).

So because target may or may not be a `Node` like I want, TS can't infer the truth, and I need to assert.

`contains(e.target as Node)` appears to be the right solution.

Problem

I have roughly the following: ``` componentDidMount() { document.querySelector('body')!.addEventListener('click', this.click); } click = (e: Event) => { if (this.state.toggled) { if (!ReactDom.findDOMNode(this.someRef).contains(e.target)) { this.setState({ toggled: false }); } } }; render() { return (<CustomElement ref={(e) => { this.someRef = e; }} />) } ``` This code correctly detects whether the user clicks inside or outside the CustomElement, so far so good. However, `tsc` isn't happy with this at all: ``` error TS2345: Argument of type 'EventTarget' is not assignable to parameter of type 'Node'. Property 'attributes' is missing in type 'EventTarget'. ``` Looking at `node_modules/typescript/lib/lib.d.ts` this makes sense, since `e.target` is an `EventTarget` which appears to only define the functions for adding and removing event handlers. However MDN says e.target is "A reference to the object that dispatched the event." which sounds closer to what I want. So how do I retain the currently working functionality, while also making tsc happy (as opposed to just silencing the error)?

Original source