10

I am trying to write a function to handle both mouse and touch events. By combining both interfaces React.TouchEvent and React.MouseEvent, like:

onStart = (event: React.TouchEvent | React.MouseEvent) => {
    event.persist();
    console.log('event ', event);
    if (event.touches) {
        console.log(event.touches);
    }
    if (event.screenX) {
        console.log(event.screenX);
    }
};

The logs give me the expected output and I don't get any console error, it runs as it I expected. But I get errors on my editor:

Error:(94, 22) TS2339: Property 'screenX' does not exist on type 'MouseEvent | TouchEvent'. Property 'screenX' does not exist on type 'TouchEvent'.

and

Error:(90, 13) TS2339: Property 'touches' does not exist on type 'MouseEvent | TouchEvent'. Property 'touches' does not exist on type 'MouseEvent'.

How can I use both intefaces React.TouchEvent and React.MouseEvent without all this errors?

Marco Daniel
  • 5,467
  • 5
  • 28
  • 36

2 Answers2

18

By checking for instanceof TouchEvent and instanceof MouseEvent in the condition and using the nativeEvent property inside event, it is possible to access each individual interface with no errors.

onStart = (event: React.SyntheticEvent) => {
    event.persist();
    console.log('event ', event);
    if (event.nativeEvent instanceof TouchEvent) {
        console.log(event.nativeEvent.touches);
    }

    if (event.nativeEvent instanceof MouseEvent) {
        console.log(event.nativeEvent.screenX);
    }
};
Jun Liu
  • 3
  • 2
Marco Daniel
  • 5,467
  • 5
  • 28
  • 36
3

I will use type predicates of TypeScript. Code is more readable.

E.g.

import React, { Component } from 'react';

function isTouchEvent(e: React.TouchEvent | React.MouseEvent): e is React.TouchEvent {
  return e && 'touches' in e;
}

function isMouseEvent(e: React.TouchEvent | React.MouseEvent): e is React.MouseEvent {
  return e && 'screenX' in e;
}

export default class MyComponent extends Component {
  onStart = (event: React.TouchEvent | React.MouseEvent) => {
    event.persist();
    if (isTouchEvent(event)) {
      console.log(event.touches);
    }
    if (isMouseEvent(event)) {
      console.log(event.screenX);
    }
  };

  render() {
    return <div>my component</div>;
  }
}
Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • 3
    what is the benefit of this solution vs the previous one which is simpler? what are you gaining with all this extra code, that the previous can't handle? (curious question) – ncubica Sep 16 '21 at 16:40