Reusing dynamic parameter types in TypeScript for other parameters

I'm currently working on a TypeScript project and am in the process of defining a function to attach event handlers to multiple events efficiently.

Instead of seeking guidance on whether my approach is ideal, I am more interested in learning how to implement it effectively. My concept involves creating a simple function that accepts the event types, the event receiver, and the callback function as parameters.

Here's an example of what I have in mind:

const addListeners = (events, htmlElement, handler) = { ... };

addListeners(['click', 'touchstart'], btn, eventType => {
  console.log(`Handling ${eventType} event`);
});

In this setup, I aim to provide the event type back to the handler so that it can execute different actions based on the specific event type it encounters.

The challenge I face is determining how to restrict TypeScript to only allow the values specified in the first argument of the addListeners function for the parameter received by the handler.

This is my current approach:

const addListeners = <E extends keyof HTMLElementEventMap, Events extends Array<E>>(events: Events, htmlElement: HTMLElement, handler: (event: string) => void): void => {
  events.forEach(e => {
    htmlElement.addEventListener(e, () => {
      handler(e, htmlElement);
    });
  });
};

My focus lies on refining the (event: string) => void aspect (the last parameter). While I believe there should be a solution, it eludes me at the moment.

Answer №1

To specify the desired action, consider using

"click" | "touchstart"
. Essentially, this creates a union of options within the array. This can be achieved by accessing specific elements in the array with the use of number:

const addListeners = <E extends keyof HTMLElementEventMap, Events extends Array<E>>(events: Events, htmlElement: HTMLElement, handler: (event: Events[number]) => void): void => {

However, why go through all that trouble when you already have the necessary elements as E:

const addListeners = <E extends keyof HTMLElementEventMap, Events extends Array<E>>(events: Events, htmlElement: HTMLElement, handler: (event: E) => void): void => {

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

Cypress terminal issue: Cannot find property in 'cy & CyEventEmitter' type

Tech stack: Angular v15 and Cypress V12 Despite successful runs of my component and end-to-end tests, I encounter peculiar terminal errors while running the tests. The issue could potentially stem from my Cypress configuration for shared commands. Here ...

Guide to integrating and utilizing a personalized JavaScript file within TypeScript components in an Angular 2 application

I have created a standard Angular 2 App using angular-cli. Now, I am trying to incorporate a custom .js file into it. Here is a simplified version of what the file looks like: 'use strict'; var testingThing = testingThing || {}; testingThing. ...

TypeScript - create an Interface that must have either the error field or the payload field, but

My Action type has the following requirements: MUST have a field type {String} CAN include a field payload {Object<string, any>} CAN include a field error {Error} Constraints: IF it contains the field payload THEN it cannot contain the field er ...

Unexpected outcome when returning a map

Encountered a puzzling issue that requires immediate clarification. When I input the following code into my project: this.metadata = json.metadata.map((x) => {return new Metadatum(x);}); console.log(this.metadata[0].value); The output consistently sho ...

Creation of an indexed database with Dexie was unsuccessful

I am currently working on an Angular application where I am encountering an issue with creating an indexed database. The database is not being created as expected. Below is a snippet of the code responsible for inserting entries into the database: creat ...

Having trouble integrating CKEditor into a React Typescript project

Error: 'CKEditor' is declared but its value is never read.ts(6133) A declaration file for module '@ckeditor/ckeditor5-react' could not be found. The path '/ProjectNameUnknown/node_modules/@ckeditor/ckeditor5-react/dist/ckeditor.js& ...

What is the best way to utilize *ngSwitchWhen in a TypeScript environment?

I am currently working with Ionic2 and Angular2 and encountering an issue while trying to implement a segment using ngSwitchWhen. Unfortunately, the functionality is not working as expected and I am receiving an error message. How can I resolve this issue ...

The cucumber step definition will wait until a specific value in mongo has been marked as "COMPLETED"

When initiating a conversion using a starting conversion service, there is a field in my Mongo database that tracks the status of the conversion: ready, runningA, runningB, DONE. How can I create a step definition that will pause execution until the statu ...

Change object properties dynamically to meet requirements in TypeScript

Let's say I have a function that outputs the following: interface result { A?: string; B?: string; C?: string; } When using an array parameter in a function, how can I make certain return parameters non-nullable and required? For example: funct ...

"Encountering issues with the functionality of two Angular5 routers

main.component.html [...] <a routerLink="/company-list">Open</a> [...] <main> <router-outlet name="content"><router-outlet> </main> [...] app.compoment.html <router-outlet><router-outlet> app.routing.modu ...

the Vue ref attribute is struggling to accurately determine the data type

Are you looking to include an additional property in a composeable method, but encountering an error stating property 'isActive' does not exist on type '{ id: string; text: string; }' Below is the code snippet: import { ref, type Ref } ...

The generated code is unable to import the file compiled by Clasp

I am encountering an issue with my TypeScript files in my Google App Project. Here is a breakdown of my files: src/main.ts function main(): void { console.log('main'); hello(); } src/other.ts console.log('hello world'); ...

The response parser in Angular 7 is failing to function correctly

Hey, I recently updated my Angular from version 4.4 to the latest 7 and after encountering several errors, I was able to get my service up and running. However, I'm facing an issue with my output parser function which is supposed to parse the login re ...

In Typescript, the function is expected to return a string rather than using the syntax of `() -> string`

Currently, I am attempting to implement the following code snippet for browser detection. However, I am encountering an error in relation to browserData, which states: Type '{ browserName: () => string; browserVersion: string | null; operatingSys ...

Issues with endpoints not functioning after importing a NESTJS module

Could someone please explain why the appController is functioning correctly while the itemsController, imported from a module, is not? I have been learning NestJS and followed the documentation as instructed. The appController is working fine with its unc ...

Vuetify's v-data-table is experiencing issues with displaying :headers and :items

I'm facing an issue while working on a Vue project with typescript. The v-data-table component in my Schedule.vue file is not rendering as expected. Instead, all I can see is the image below: https://i.sstatic.net/AvjwA.png Despite searching extensi ...

Set the mat-option as active by marking it with a check symbol

Currently, I am utilizing mat-autocomplete. Whenever a selection is made manually from the dropdown options, the chosen item is displayed with a distinct background color and has a checkmark on the right side. However, when an option in the dropdown is se ...

In React TypeScript, the property types of 'type' are not compatible with each other

I have a unique custom button code block here: export enum ButtonTypes { 'button', 'submit', 'reset', undefined, } type CustomButtonProps = { type: ButtonTypes; }; const CustomButton: React.FC<CustomButtonProp ...

Issue with BehaviorSubject<Object[]> causing incorrect array data upon initial subscription

I am facing an issue with a BehaviorSubject where the first .subscribe callback is returning an Array with 6 Objects. Strangely, in console output, it shows length: 6, but every for-loop I iterate through the array only runs 5 times and even when I log arr ...

Can we improve the coding of this as it seems inefficient and uses up too much room?

Do you think there is a more efficient way to write this code? It seems quite impractical and takes up a lot of space. Essentially, it's about the random chance of obtaining a rarity, like acquiring an Uncommon sword. if (Math.random() * 100 < 100 ...