Finding the ID of the element that was clicked with strict typing

Consider a scenario where we aim to record the ID attribute of a clicked element using the TypeScript code snippet below:

onClick(event) {
  console.log(event.target.attributes.id.nodeValue);
}

The function above takes the clicked object as an argument, however, the type in this instance is any. Upon checking the data type of event, it returns object. To address this, I would update my code as follows:

onClick(event: object) {
  console.log(event.target.attributes.id.nodeValue);
}

Post alteration, an error surfaces in VS Code as shown below:

https://i.sstatic.net/5ch8E.png

This leads to the question - why does using the parameter type any work smoothly, enabling the console to successfully log the desired ID without errors, while opting for a strict object type causes compilation issues? What could be causing this discrepancy?

The relevant HTML segment looks like this;

<h1 id="foo" (click)="onClick($event)">...</h1>

Answer №1

When I checked the result of typeof event, it returned as object.

This is JavaScript runtime code, utilizing the typeof operator that always returns "object" for all objects (including null).

I realized that my code needed some modifications when I encountered an error in VS Code like the one mentioned below.

It's worth noting that plain objects do not contain a target property.

For a click event, the type of the event object is MouseEvent. If you are using jQuery or Angular to attach the event, it will rely on the DOM's MouseEvent. In this case, using event.currentTarget.id or event.target.id is recommended over accessing the attributes collection and nodeValue since the id attribute is a reflected property.

Despite this, the MouseEvent interface considers both currentTarget and target properties as EventTarget, even though they are essentially referring to an Element. This deviation prompts the need for a type assertion:

onClick(event: MouseEvent) {
    console.log((event.target as Element).id); // Alternatively, you can use `(event.currentTarget as Element).id`
}

Playground link

While type assertions may not be ideal, they are sometimes necessary for such scenarios. There are alternative ways to perform the same assertion, like the examples provided below:

onClick({target}: {target: Element}) {
    console.log(target.id);
}
// or
onClick({currentTarget}: {currentTarget: Element}) {
    console.log(currentTarget.id);
}

Playground link

You could introduce a reusable type for more clarity:

interface ElementMouseEvent extends MouseEvent {
    currentTarget: Element;
    target: Element;
}

Utilizing this custom type would still involve making an assertion but ensures safety:

onClick(event: ElementMouseEvent) {
    console.log(event.target.id); // Or `event.currentTarget.id`
}

Playground link

If you desire complete type safety, you could implement a type assertion function that throws a clear error if the assertion fails:

function assertIsElement(obj: object | null): asserts obj is Element {
    if (!(obj instanceof Element)) {
        throw new Error(`Object is not an Element instance`);
    }
}
// ...
onClick({currentTarget}: MouseEvent) {
    assertIsElement(currentTarget);
    console.log(currentTarget.id);
}

Playground link

In cases where you have control over the usage of onClick and are certain it pertains to an Element, this level of strictness may be unnecessary.

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

Tips for updating the value within a textfield in HTML

I am looking to dynamically update the value displayed in my Revenue textfield by subtracting the Cost of Goods from the Sales Price. I have included an image of the current layout for reference, but I want the Revenue field to reflect the updated value af ...

Angular: Nodemailer is encountering an abundance of runtime errors

Within my Angular project, I am attempting to utilize Nodemailer for sending emails. The initial issue arises when I try to import (after running npm i --save) as numerous errors occur when executing ionic serve. It's important to note that right aft ...

Amazon Lex: Transforming Speech to Text with Audio Technology

Is there a JavaScript SDK provided by Amazon for converting audio files to text using Amazon Lex? I am currently working on a Node.js application and would like to achieve this functionality. ...

Tips for repeatedly clicking a button over 50 times using Protractor

Is it possible to click the same button more than 50 times using a loop statement in Protractor? And will Protractor allow this action? Below is my locator : var nudge= element(by.xpath("//a[@class='isd-flat-icons fi-down']")); nudge.click(); ...

Creating an HTTP interceptor in Backbone: A step-by-step guide

After gaining experience with backbone, I decided to delve into learning angular. The features of angular really caught my interest, especially the HTTP interceptor. I began thinking about how to implement this functionality in backbone to display a spin ...

I am experiencing some issues with React Router V4's functionality

I am currently developing a web application where I intend to showcase user details on the same page using routers when they are clicked. Below is my index.js file: window.React = React; render(<div> <Menu/><MainMenu/><App/>&l ...

Is there a way to access various history.pushState events when using window.popState in JavaScript?

In my code, there are two pushStates that I need to read separately and execute different functions for. However, when the form is not submitted, the related pushState does not trigger and results in this error: Uncaught TypeError: Cannot read property &ap ...

React - The issue with my form lies in submitting blank data due to the declaration of variables 'e' and 'data' which are ultimately left unused

Currently, I'm working on incorporating a form using the react-hook-form library. Despite following the documentation and utilizing the handleSubmit function along with a custom Axios post for the onSubmit parameter like this: onSubmit={handleSubmit( ...

Are $(function() { }) and $(document).ready(function() { }) the same function under the hood?

Similar Question: What sets apart these jQuery ready functions? Do $(function(){}); and $(“document”).ready(function(){}); have the same meaning? Beginning javascript code with $(function, etc. This day, as I was examining some jav ...

What is the best way to format the information when using response.send() in express.js?

I need help with customizing the content I'm returning in the app.post() method. Is there a way to do this? Below is an example of the app.post() code: app.post("/",function(req,res){ const query = req.body.cityName; const cityName = query.charA ...

Troubleshooting problems with building an Angular project containing Angular Slickgrid

After successfully migrating my project from Angular 13 to Angular 17 and updating angular-slickgrid from version 4.1.4 to 7.5.0, I am facing a build error that I cannot resolve. I have addressed all other errors except for one: When compiling with Angular ...

What are the steps to troubleshooting using VS Code and Chrome browser with Webpack?

Can anyone provide guidance on how to debug webpack in VS Code with the Chrome browser? As a beginner in programming, I'm struggling because webpack minifies everything into one line which makes traditional debugging methods ineffective. I haven' ...

What is the best way to configure eslint or implement tslint and prettier for typescript?

In my React/Redux project, I recently started integrating TypeScript into my workflow. The eslint configuration for the project is set up to extend the airbnb eslint configurations. Here's a snippet of my current eslint setup: module.exports = { // ...

Unexpected behavior observed with Async/Await

I am currently learning how to use Async/Await, which is supposed to wait until the Await function finishes executing before moving on with the code. However, I have encountered an issue where my code stops completely after using Await. Here is the method ...

Experiencing a snag with Angular2 and angular2-jwt: encountering an issue with AuthHttp where the JWT must consist

Encountering an issue with AuthHttp despite receiving a valid token from the authentication. The token has been confirmed as valid on . Currently working with Angular 4. Here is my code: Sign-In Code signIn(login: string, password: string) { this.U ...

Why is the Material Ui code functioning flawlessly in Codepen but not in VSCODE?

In my ReactJS project, I am using Material-UI to create "Material Tabs". The code works fine in SANDBOX but not in my VS CODE. What could be the issue? I have checked that Node is installed and all dependencies versions from NPM are up to date. I also tri ...

Is there a way to prevent ng-template-loader from scanning image src's?

Currently, I am beginning to incorporate webpack into my development workflow for an angular project. To create my templateCache, I have had to include the ng-template-loader. Below is a snippet of my webpack configuration: { test: /\.html$/, loa ...

Generating a form structure from json containing repeated inputs: Control with path formArray could not be located

Currently, I am in the process of constructing a form using JSON data. My backend is implemented with Spring Boot, which returns the following object to an Angular frontend: { "controls": [ { "name": "genre", ...

Having trouble getting array push to work in Internet Explorer 5 with JavaScript?

Every time I attempt to populate the select options into the optStored array using array push, the array remains empty. The code works fine in Chrome, Firefox, and Safari but not in Internet Explorer. Is there a workaround for this issue or is it something ...

Ways to limit the extent of inline CSS styling?

I am working on a project where I need to apply unique CSS to each item in a list dynamically. Each item will have its own set of CSS rules specifically tailored to its elements. <div id="thing1" class="vegas"> <style> p { font-size: ...