Creating dynamic function parameters with predefined type extraction

Is there a possibility to generate dynamic type that could substitute two parameters, for example, in

on: (eventName: EventName, callback: (data: any) => void) => void
, with something like
on: (DynamicParams<EventName>) => void
, where it can retrieve the type of callback from a predefined set and utilize it instead of the generic any type?

I believe an easier explanation would involve some coding.

Let's assume I have an array containing different event types:

const events = ['loaded', 'changed'];

type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType[number];

type EventName = ArrayElement<typeof events>

and a function that should only execute when a specific event notification is triggered;

const on = (eventName: EventName, callback: (data: any) => void) => {}

However, I want to be able to employ this function with callbacks that expect varying parameter types seamlessly, without manual type checks or casting, such as:

on('loaded', (list: Entry[]) => {
  // perform actions on loaded array elements;
}

on('changed', (index: number) => {
  // carry out tasks based on index of a changed entry;
}

Is there a method to devise a mapped type that would take EventName as input and yield a specific return type corresponding to each event?

Perhaps something along these lines:

const on(eventName: EventName, DynamicMethod<'eventName'> => void) => {}

const on(DynamicParams<'eventName'>) => {}

If we had to replace the event object and formulate a type in its stead:

type events = [
  {
    name: 'loaded',
    method: (list: Entry[]) => void

  },
  {
    name: 'changed',
    method: (index: number) => void
  }
]

Though uncertain about extracting the 'name' values instead of their types.

Answer №1

If you create a mapping of event names to their corresponding data types:

type EventMap = {
    loaded: Entry[];
    changed: number;
};

You can introduce generics to the function on:

const on = <E extends EventName>(eventName: E, callback: (data: EventMap[E]) => void) => {}

on('loaded', (list) => {
//            ^? Entry[]
});

on('changed', (index) => {
//             ^? number
});

Visit Playground

Answer №2

To achieve this functionality, there are two possible approaches:

Option one involves using call signatures:

interface OnEvent {
  (eventName: 'loaded', callback: (list: Entry[]) => void): void;
  (eventName: 'changed', callback: (index: number) => void): void;
}

const on: OnEvent = (eventName, callback) => {
    // Determine how to register the event here...
}

The second option is to use function overloads:

function on(eventName: 'loaded', callback: (list: Entry[]) => void): void;
function on(eventName: 'changed', callback: (index: number) => void): void;
function on(eventName: string, callback: (data: any) => void) {
    // Determine how to register the event here...
}

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

What methods do typescript libraries use to interpret types during runtime?

After compiling source code from TypeScript to JavaScript, type annotations are removed and it becomes impossible to verify the type of a variable at runtime. Despite this limitation, there exist TypeScript libraries that alter their behavior based on the ...

Eliminate all TypeScript type annotations and assertions from your codebase

Given a project that needs to transition from TypeScript to Babel, with files containing essential typing information that cannot be disregarded by Babel. How can we automatically remove TS type annotations and assertions from the entire code base? Is th ...

Issue with MIME handling while utilizing Vue-Router in combination with Express

Struggling to access a specific route in Express, I keep encountering an error in my browser. Additionally, when the Vue application is built, only the Home page and the 404 page seem to work properly, while the rest display a default empty HTML layout. F ...

Combining multiple arrays of objects using multiple keys with Angular 9 and Typescript

I have two JSON objects (displayed here with JSON.stringify(array of objects)) GPRows data is [ { "shopName":"Testing One", "state":"NSW", "yearMonth":"20203", "id& ...

Tips for implementing a request timeout in Typeorm/Typescript

Today, when using Typeorm with Postgres, there seems to be an issue where the behavior of getManager().query(...) getRepository().createQueryBuilder(...).getMany() is causing it to wait indefinitely for a response. Is there a way to set a timeout for t ...

The Angular tutorial for the "Tour of Heroes" is experiencing issues with aligning the heroes' list properly

I am currently working on the Angular tour of heroes tutorial. However, I am facing an issue when trying to display the list of heroes as it appears like this: https://i.sstatic.net/AGnzJ.png It is strange because even though the CSS/HTML/TS code from the ...

Deploying Firebase functions results in an error

Just recently started exploring Firebase functions. Managed to install it on my computer, but running into an error when trying to execute: === Deploying to 'app'... i deploying firestore, functions Running command: npm --prefix "$RESOURCE_ ...

When invoking a service repeatedly in Angular within a loop, the result is returned on the second iteration rather than the first

I've run into an issue where I'm attempting to invoke a service in Angular within a for loop and store the result in a Map. map = new Map<string, string[]>(); this.effectivitiesList = this.trimEffectivities.split(","); for (let ...

Is there a way to incorporate timeouts when waiting for a response in Axios using Typescript?

Can someone assist me in adjusting my approach to waiting for an axios response? I'm currently sending a request to a WebService and need to wait for the response before capturing the return and calling another method. I attempted to utilize async/aw ...

Creating packages for multiple Typescript projects that rely on a shared local module

I am currently developing a series of VSTS extensions, with each extension being its own independent Node project complete with its own package.json file and node_modules folder. The structure of the folders is as follows: - MyExtension - package.json ...

Tips on creating a union of tuple types in a way that maintains the association of variable types even after destructuring

Is it possible to specify the data types of tuples in a way that allows for type inference as illustrated in the comments within the code snippet below? declare const tuples: [number, null] | [null, number]; const [a, b] = tuples; const fun = () => ...

Leveraging @Inputs with Angular 2's <router-outlet> component for optimal functionality

I am working on a webpage with a sub-navigation feature that displays subviews below a main view. I am looking for a way to pass an object to the subviews using the <router-outlet> so that I only need to retrieve the data once in the main component a ...

The v-if directive doesn't get updated properly when a watcher modifies an enum data variable

I'm encountering an issue with the usage of v-if alongside watchers and data in Vue. Below is a snippet from my Single File Component (SFC): <script lang="ts"> // imports ... export default defineComponent({ data() { retur ...

Creating a bump chart using structured data: A step-by-step guide

The bump chart example provided by ECharts includes sections with randomly generated data, which can be confusing for those unfamiliar with JavaScript or TypeScript. What would the code appear like if it didn't rely on data generation? ...

Typescript polymorphism allows for the ability to create various

Take a look at the following code snippet: class Salutation { message: string; constructor(text: string) { this.message = text; } greet() { return "Bonjour, " + this.message; } } class Greetings extends Salutation { ...

Why is it that my TypeScript isn't permitting the definition of Tuple Types?

When attempting to define a tuple type in my code, an error is being thrown. Is there a specific configuration within my Node.js application that needs to be adjusted in order to accept tuple types? ...

Ways to send information from a child component to its parent component when a button is clicked in the

Being new to Angular, I am faced with a challenge of organizing a large form into smaller modular components. I have created multiple child components and integrated their selectors in the main parent component. In the parent component, there is a 'sa ...

Declaring scoped runtime interfaces with Typescript

I need to create a global interface that can be accessed at runtime under a specific name. /** Here is my code that will be injected */ // import Vue from "vue"; <- having two vue instances may cause issues // ts-ignore <- Vue is only ava ...

Encountering an issue with authenticating the user: "The first parameter 'email' must be a valid string."

Currently, I am working on validating a sign-up form and authenticating user email and password using Firebase. export class SignupPage { signupForm :FormGroup; user_name :AbstractControl; user_email :AbstractControl; acc_type: AbstractControl; user_pass ...

What is the purpose of the @NgModule annotation in Angular Material?

I've been struggling with using Angular-Material Components in different components. Despite watching and reading various tutorials, I still can't seem to get them to work. The error message I keep encountering is: compiler.js:2430 Uncaught Erro ...