Manage input from either mouse or touch events based on the event type

I've encountered a challenge with my general handler function that processes both mouse and touch events. Despite my efforts, Typescript keeps issuing errors due to the distinction between mouseEvent and touchEvent.

function handleStopDrag(e: MouseEvent | TouchEvent) {
    switch (e.type) {
        case 'mouseup':
            // Error: Argument of type 'MouseEvent | TouchEvent' is not assignable to parameter of type 'MouseEvent'.
            handleMouseUp(e)
            break
        case 'touchcancel':
        case 'touchend':
            // Error: Argument of type 'MouseEvent | TouchEvent' is not assignable to parameter of type 'TouchEvent'.
            handleTouchEnd(e)
            break
    }
}

function handleMouseUp(e: MouseEvent){ ... }
function handleTouchEnd(e: TouchEvent) { ... }

How can I effectively specify the type of event based on my conditions? Is there a more efficient way to structure my code to define the event type?

Answer №1

To make TypeScript narrow the union type MouseEvent | TouchEvent without type assertion, you must utilize a type guard:

  • Using type predicates:
function isMouseEvent(e: MouseEvent | TouchEvent): e is MouseEvent {
    return e.type === 'mouseup'; // || e.type === 'click'...
}

Implementation example:

if (isMouseEvent(e)) {
    switch (e.type) {
        case 'mouseup':
            handleMouseUp(e);
            break;
    }
} else (isTouchEvent(e)) {
    switch (e.type) {
        case 'touchcancel':
        case 'touchend':
            handleTouchEnd(e);
            break;
    }
}
  • Using instanceof:

Example implementation:

if (e instanceof MouseEvent) {
    // handle MouseEvent case
    handleMouseEvent(e);
} else if (e instanceof TouchEvent) {
    // handle TouchEvent case
    handleTouchEvent(e);
}

Answer №2

Utilizing the in operator to verify the existence of a property that is not present in both Typescript enabled the system to seamlessly handle other tasks, requiring minimal effort on my part

function dragStart(e: MouseEvent | TouchEvent) {
  if ('touches' in e) {
    state.initialX = e.touches[0].clientX - state.xOffset
    state.initialY = e.touches[0].clientY - state.yOffset
  } else {
    state.initialX = e.clientX - state.xOffset
    state.initialY = e.clientY - state.yOffset
  }

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The mat-slide-toggle component does not recognize the checked binding

My angular app contains the mat-slide-toggle functionality. switchValue: {{ switch }} <br /> <mat-slide-toggle [checked]="switch" (toggleChange)="toggle()">Toggle me!</mat-slide-toggle> </div> This is how the ...

Issues with using hooks in a remote module in Webpack 5 module federation

I am attempting to create a dynamic system at runtime using Module Federation, a feature in webpack 5. Everything seems to be working well, but I encounter a multitude of 'invalid rule of hooks' errors when I add hooks to the 'producer' ...

Universal function for selecting object properties

I've recently delved into TypeScript coding and have run into a puzzling issue that has me stumped. Take a look at the code snippet below: interface testInterface { a: string; b: number; c?: number; } const testObject: testInterface = { a: & ...

Navigate Formik Fields on a Map

Material UI text-fields are being used and validated with Formik. I am looking for a way to map items to avoid repetitive typing, but encountering difficulties in doing so. return ( <div> <Formik initialValues={{ email: '&a ...

What defines a suitable application of the ref feature in React?

How can the ref attribute be effectively used in React? I understand that it is considered a shortcut that may go against the principles of React DOM, but I want to know the specifics of how and why. I'm currently evaluating if my use case justifies t ...

Adding items to the array is only effective when done within the loop

My approach involves retrieving data from an API using axios, organizing it within a function named "RefractorData()," and then pushing it onto an existing array. However, I have encountered a problem where the array gets populated within a forEach loop, a ...

Choose particular spreadsheets from the office software

My workbook contains sheets that may have the title "PL -Flat" or simply "FLAT" I currently have code specifically for the "PL -Flat" sheets, but I want to use an if statement so I can choose between either sheet since the rest of the code is identical fo ...

What is the correct way to apply type in the .call() method?

I need help finding a solution for the following issue interface IName { name:string; } let obj1:IName = { name: "LINUS" } function profileInfo (age:number,location:string):string{ return `${this.name} is ${age} years old and is from ${location ...

What are the downsides of utilizing a global function over a private static method in Typescript?

It's quite frustrating to have to write this.myMethod() or ClassName.myMethod() instead of just myMethod(). Especially when dealing with a stateless utility function that doesn't need direct access to fields. Take a look at this example: functi ...

Issues arise when upgrading from Angular 8 to 9, which can be attributed to IVY

After successfully upgrading my Angular 8 application to Angular 9, I encountered an error upon running the application. { "extends": "./tsconfig.json", "compilerOptions": { "outDir": ". ...

The data structure '{ recipe: null; }' cannot be matched with type 'IntrinsicAttributes & Recipe'

Currently, I am working on an app that integrates ChatGPT to fetch recipes based on user-input ingredients. After receiving the JSON response from CGPT, I aim to display a Recipe "Card" component. However, I encounter an error titled above when attempting ...

Unlocking the potential of the ‘Rx Observable’ in Angular 2 to effectively tackle double click issues

let button = document.querySelector('.mbtn'); let lab = document.querySelector('.mlab'); let clickStream = Observable.fromEvent(button,'click'); let doubleClickStream = clickStream .buffer(()=> clickStream.thrott ...

How to Access Static Method from Non-Static Method in TypeScript

Within my hierarchy, there is some static content present in all levels (for example, the _image). It would be ideal to access the corresponding _image without repeating code: Here's what I envision: class Actor { static _image; // Needs to be s ...

In React Typescript, there is an issue with react-router v4 where the Route component does not pass its props to the specified component

Struggling with React Router v4 and history usage in Browserrouter. Whenever attempting to access this.props.history.push("/"), the error pops up: TS2339: Property 'history' does not exist on type 'Readonly<{ children?: ReactNode; }> ...

Rearrange Material UI styles in a separate file within a React project

Currently, I am developing an application utilizing material-ui, React, and Typescript. The conventional code for <Grid> looks like this: <Grid container direction="row" justifyContent="center" alignItems="center&q ...

Improprove the types generated from GraphQL responses

I am facing a major challenge with the types while using GraphQL. My intention is to send a request and store the result in a React state with a well-defined type. However, I want to avoid declaring it as const [animals, setAnimals] = useState<AnimalsLi ...

What is the process for establishing the default type for an Activity Entity in Microsoft Dynamics?

Currently in the process of restructuring a portion of script code associated with the Fax Activity Entity within Microsoft Dynamics. Within the script code, the following can be found: document.getElementById("regardingobjectid").setAttribute("defaulttyp ...

What would be a colloquial method to retrieve the ultimate result from the iterator function?

I've got a rather complex function that describes an iterative process. It goes something like this (I have lots of code not relevant to the question): function* functionName( config: Config, poolSize: number ): Generator<[State, Step], boo ...

Is it possible to deactivate input elements within a TypeScript file?

Is it possible to disable an HTML input element using a condition specified in a TS file? ...

"Encountering the error of 'require is not defined' in an Electron-React-Webpack-Typescript application when utilizing

When I add these lines to /src/renderer.ts in an Electron-React-Webpack-Typescript app: ipcRenderer.on('messageFromMain', (event, message) => { console.log(`This is the message from the second window sent via main: ${message}`); }); I encou ...