How can one extract the "Element" -type value from "Element.parentNode" rather than from "Node & ParentNode"?

Here is a snippet for event delegation from :

document.addEventListener(eventName, function(e) {
    // loop parent nodes from the target to the delegation node
    for (var target = e.target; target && target != this; target = target.parentNode) {
        if (target.matches(elementSelector)) {
            handler.call(target, e);
            break;
        }
    }
}, false);

I am attempting to rewrite it in TypeScript with type safety (specifically for handling click events):

export default function delegateClickEventHandling(
    {
      clickTargetSelector,
      container = document
    }: {
      clickTargetSelector: string;
      container: HTMLElement | Document;
    },
    handler: (event: MouseEvent) => void
): void {

  container.addEventListener("click", (event: Event): void => {

    if (!(event instanceof MouseEvent)) {
      return;
    }

    for (
        let targetParentNode: Element | null = event.target as Element;
        isNotNull(targetParentNode) && targetParentNode !== event.currentTarget;
        targetParentNode = targetParentNode.parentNode
    ) {

      if (targetParentNode.matches(clickTargetSelector)) {
        handler(event);
      }
    }
  }, false);
}

The TypeScript compiler is throwing an error:

TS2322: Type '(Node & ParentNode) | null' is not assignable to type 'Element | null'.
Type 'Node & ParentNode' is not assignable to type 'Element | null'.
Type 'Node & ParentNode' is missing the following properties from type 'Element':
 assignedSlot, attributes, classList, className, and 64 more.

The .matches() method belongs to the Element interface - it cannot be called on type Node & ParentNode. What should be done in this case?

If

targetParentNode = targetParentNode.parentNode as Element
is correct, please provide an explanation.

P. S. Please avoid using any, object, or omitting type annotations.

Answer №1

To solve this issue, simply convert targetParentNode.parentNode to type Element.

The updated for loop will now look like this:

for (
    let targetParentNode: Element = event.target as Element;
    targetParentNode !== event.currentTarget;
    targetParentNode = targetParentNode.parentNode as Element
) {

  if (targetParentNode.matches(clickTargetSelector)) {
    handler(event);
  }
}

PlaygroundLink

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

Is it possible to set the input form to be read-only?

I need to create a "read-only" version of all my forms which contain multiple <input type="text"> fields. Instead of recoding each field individually, I'm looking for a more efficient solution. A suggestion was made to use the following: <xs ...

Separate and add on the change validity status of an AngularJS form

If you want to test it out, check this jsFiddle link: HERE (it's recommended to view on a new jsFiddle, refer to the EDIT section of this post) I've noticed what seems like a bug in AngularJS or at least an unexpected behavior. When I detach a f ...

Selecting meteor.js user logout functionality

Is there a reliable method for detecting when a user logs out of the website? I have some maintenance tasks that need to be handled upon logout. The website is built using meteor.js user accounts. I will also be implementing validation features, so it&apo ...

Show concealed content for individuals who do not have javascript enabled

One of the challenges I faced was creating a form with a hidden div section that only appears when a specific element is selected from a list. To achieve this, I utilized CSS to set the display property of the div to 'none' and then used jQuery t ...

What steps do I need to take to show WebStorm that my userscript is successfully loading jQuery?

My situation involves a userscript that utilizes the @require directive in the metadata block to load jQuery from an external source: // @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js It seems like WebStorm isn't awar ...

What is the best method to transfer information between main.js and a specific directory?

Is there a way to efficiently pass data between the main and directory components? I would like to automatically activate the directive when main.js loads. Directive code: angular.module('dmv.shared.components'). directive('doImportPackag ...

Can Node.js endpoints effectively handle the garbage collection of new class instances?

Just diving into node.js I'm currently dealing with a lengthy and messy function that constructs a CYPHER query for Neo4j. I am considering transforming it into a class, complete with methods, along with a corresponding mocha spec. The expected usag ...

Obtaining Runtime Inputs from the Command Line

I have been using a unique Vue SPA boilerplate found at this link, which utilizes webpack as its foundation. During the development process or when deploying the application, I have successfully utilized process.env.NODE_ENV to differentiate between a dev ...

In the realm of Bootstrap 4, the nav collapsing animation briefly hesitates when opening but smoothly closes without any interruptions

The menu expands smoothly when opened but has a slight pause before continuing to slide down. Closing the menu seems to be smoother compared to opening it. .navbar { padding: 0; float: right; } .navbar.fixed-top { left: auto; } .navbar-menu { ...

The Angular Nativescript framework is lacking necessary properties for the 'Observable<>' type

Whenever I try to set my function as getCalendarEvents(): Observable<Array<CalendarEvent>>{, I encounter an error message stating Type 'Observable<CalendarEvent[]>' is missing the following properties from type 'CalendarEve ...

Execute function asynchronously after useEffect has completed

I'm curious about how to run a function following the use of useEffect to fetch data, where the function manipulates the retrieved data. import React, { useState, useEffect } from 'react'; const Result = (props) => { const [ playerN ...

Dispatch not invoking Thunk Action - utilizing Typescript

I am currently using React, Redux, Redux-Thunk, and Typescript as a beginner. I have encountered an issue where when I call an action with a thunk, the action is being called (confirmed with a console.log) but the dispatch is not happening. I have connecte ...

Angular time-based polling with conditions

My current situation involves polling a rest API every 1 second to get a result: interval(1000) .pipe( startWith(0), switchMap(() => this.itemService.getItems(shopId)) ) .subscribe(response => { console.log(r ...

Tips for utilizing Vue 'component' with just Vue added as a page add-on using <script>:

I am trying to incorporate a Vue component called vue-timeago: import VueTimeago from 'vue-timeago' Vue.use(VueTimeago, { name: 'Timeago', // Component name, `Timeago` by default locale: undefined, // Default locale locales: { ...

In JavaScript, the code is designed to recognize and return one specific file type for a group of files that have similar formats (such as 'mp4' or 'm4v' being recognized as 'MOV')

I am working on a populateTable function where I want to merge different file types read from a JSON file into one display type. Specifically, I am trying to combine mp4 and m4v files into MOV format. However, despite not encountering any errors in my code ...

A guide to implementing typescript with Next.js getStaticProps

I have Next.js set up with the TypeScript feature enabled Currently, I am attempting to utilize the getStaticProps function following the guidelines outlined here: https://nextjs.org/docs/basic-features/typescript Utilizing the GetStaticProps type export ...

Require assistance with Dhtmlx and Wijmo grid context menus, as well as touch events, specifically when utilized on an iPhone's Safari browser

I recently created a web application utilizing DHTMLX 5.0 and Wijmo grid. Everything functions smoothly when accessed on Chrome for Android, including the context menu which is opened with a touch-'press and hold' gesture. However, I have encount ...

Include the aria-labelledby attribute in the jQuery Datatable Pagination

Check out the HTML output created by the Jquery Datatable plug-in for pagination(https://datatables.net/plug-ins/pagination/full_numbers_no_ellipses): <div class="dataTables_paginate paging_full_numbers" id="my-table_paginate" aria-l ...

Display file names in a file input using Angular through coding techniques

Hi there, I'm currently working on a project using Angular15, and one of the features involves populating a table with data about team members. When adding a new member, a button is clicked to open a modal window where users can input their informat ...

Receiving a 401 error is a common issue when working with Angular

I am encountering an issue with HttpClient. Every time I attempt to send a POST request from my frontend, I consistently receive a 401 Unauthorized error without even reaching the endpoint. I attempted using incognito mode to rule out any potential cache-r ...