Creating a TypeScript function definition that adapts dynamically based on the input functions

Is it feasible to alter the type of something depending on the value of an argument passed to a function? I am in need of this specific type for an event emitter with callback. For instance:

interface IUser {
  name: string
}

type CallbackType = /* A dynamic Type for the Callback */

// Type for CallBack should be (user: IUser) => any when used for event1
use("event1", (user) => { /* Verify that event1 is utilized, and add only 1 argument to the callback type  */ })

// Type for CallBack should be (email: string, password: string) => any when used for event2
use("event2", (email, password) => { /* Confirm that event2 is utilized, and include 2 arguments in the callback type */ })

Therefore, is there a method to determine which event is being used and assign the appropriate type to the callback?

Answer №1

The most straightforward approach is to utilize overloads.


type Callbacks = {
  (name: "event1", cb: (u: IUser) => void): void
  (name: "event2", cb: (email:string, pass: string) => void): void
}

let use: Callbacks = null!;
//for event1 the type Callbacks should be (user: IUser) => any
use("event1", (user) => { /* verify that event1 is used, therefore only add 1 argument to the callback type */ })

//for event2 the type Callbacks should be (email: string, password: string) => any
use("event2", (email, password) => { /* verify that event2 is used, hence add 2 arguments to the callback type */ })

Playground Link

For more complex scenarios, like having callbacks in another type or intricate conditions, you may want to consider tuples in rest parameters and conditional types. However, based on your question, that would likely be excessive.

Answer №2

Below is an example showing how to use types in TypeScript:

type CallBackEvent1 = (event: "event1", cb: (user: IUser) => void) => void;
type CallBackEvent2 = (
  event: "event2",
  cb: (email: string, pass: string) => void
) => void;

type CallBack = CallBackEvent1 | CallBackEvent2;

const callBack1: CallBack = (event: "event1", cb: (user: IUser) => void) =>
  undefined;
const callBack2: CallBack = (
  event: "event2",
  cb: (email: string, pass: string) => void
) => undefined;

const wrongCallBack: CallBack = (event: "event2", cb: (user: IUser) => void) =>
  undefined;
// Type '(event: "event2", cb: (user: IUser) => void) => undefined' is not assignable to type 'CallBack'.
//   Type '(event: "event2", cb: (user: IUser) => void) => undefined' is not assignable to type 'CallBackEvent1'.
//     Types of parameters 'event' and 'event' are incompatible.
//       Type '"event1"' is not assignable to type '"event2"'.ts(2322)

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

Creating TypeScript modules for npm

I have been working on creating my first npm module. In the past, when I used TypeScript, I encountered a challenge where many modules lacked definition files. This led me to the decision of developing my module in TypeScript. However, I am struggling to ...

The attempt to combine an array of elements with another array using FieldValue.arrayUnion() in Firestore was unsuccessful

My cloud function is triggered when a specific event occurs. Within the function, I receive an array of strings like this example: let h:string[] = ["foo","bar","baz"]. When I attempt to update an array field within my document using names: admin.firestor ...

Issue with Angular2-Meteor application: unable to establish connection with MySQL database through Meteor framework

Having trouble connecting to a MySQL database with Meteor using nodets:mysql and encountering the following error message: Unhandled rejection Error: No data can be retrieved from your database, please verify your permissions Here's the snippet of c ...

React-query v5 - Updating or fetching outdated query

I am currently using the Tanstack/react-query v5.12.2 library and I am facing an issue with invalidating or refetching an inactive query using the useQueryClient() function. It seems that something has changed in version 5 of the library. I have tried sett ...

Avoid automatic restart of NestJS server upon modifying specific directories

When running my application in watch mode using the nest start --watch command, the server automatically restarts whenever a source file is changed. While this behavior is expected, I am looking for a way to exclude certain directories or files from trigg ...

Tips for integrating personalized arrow buttons into Alice-Carousel

Currently, I am in the process of creating a carousel component using alice-carousel (https://github.com/maxmarinich/react-alice-carousel/blob/master/README.md), but I am encountering some difficulties when trying to customize the arrows. The code snippet ...

Create a TypeScript array of objects that mirrors a Java List<Map<String, String>>

In my Java function, the argument type is List<Map<String, String>>. To perform a fetch call from a TypeScript file, I need to declare a variable whose type corresponds to List<Map<String, String>>. As TypeScript does not have a bu ...

Hiding the line connector between data points in ChartJs

I recently took over a project that includes a line chart created using Chart.js by the previous developer. My client has requested that I do not display a line between the last two data points. Is this possible with Chart.js? I have looked through the doc ...

Publishing Typescript to NPM without including any JavaScript files

I want to publish my *.ts file on NPM, but it only contains type and interface definitions. There are no exported JavaScript functions or objects. Should I delete the "main": "index.js" entry in package.json and replace it with "main": "dist/types.ts" inst ...

Displaying inner arrays in an Angular2 MatTable

Welcome to my initial post on Stack Overflow, where I hope to communicate my query clearly. I am currently attempting to develop a table with dynamic columns. However, I am encountering difficulty in comprehending how to bind matColumnDef to a specific el ...

Can a type be referenced using the generic name?

My selection includes: export type DocumentType = | Item | List | User export type DocumentInputType = | ItemInputType | ListInputType | UserInputType I want to develop a feature that can determine the input type based on the document type wi ...

When implementing Angular 6, using a shared module within individual lazy-loaded modules can lead to a malfunctioning app when changes are

Hey there, I've encountered a strange problem that didn't occur when I was using Angular 5. Let me explain the situation: In my App routing module, I have: { path: 'moduleA', pathMatch: 'full', loadChildren: &ap ...

What is the best way to transfer the API Response Time from one Fetch function to a separate asynchronous function?

After successfully obtaining the API Response Time (duration) using the 'makeAPICall' function, I am now faced with the task of passing this duration variable value to another asynchronous function. Can anyone assist me in finding a solution to a ...

Having trouble getting React app to recognize Sass properly

I have been working on developing a React app using TypeScript and the SASS preprocessor. Here is an example of my code: // Button.tsx import React from 'react'; import './Button.scss'; export default class Button extends React.Compone ...

When conducting Angular testing using Karma and Jasmine, a method that makes use of HttpClient.get may result in undefined values in the service spec. However, it successfully

Issue with Angular service method retrieving data from database during testing In myservice.ts, I have a method named getEvents() that creates an array, fetches data from the database using http.get, fills the array, and returns it. However, when I try to ...

struggling to access the value of [(ngModel)] within Angular 6 component

When working in an HTML file, I am using ngModel to retrieve a value that I want to utilize in my component. edit-customer.component.html <input id="userInfoEmail" type="text" class="form-control" value="{{userInfo.email}}" [(ngModel)]="userInfo.email ...

Data is not displaying correctly in the Angular Material Table

I'm currently trying to build a mat table based on an online tutorial, but I'm facing a problem where the table appears empty even though I have hard coded data. As someone new to Angular and HTML/CSS, I'm struggling to understand why the ma ...

Getting into a dynamic named property inside another object in angular can be achieved by utilizing bracket notation

I encountered an issue in my Angular 8 project where I create an object from a JSON, but there is a dynamic property whose name is unknown until runtime. This causes problems when trying to access the value of that dynamic property within another object, l ...

Component fails to navigate to the page of another component

Hello there. I am facing an issue where the button with routelink in the RegistrationComponent is not routing to the page of LogInComponent and I cannot figure out why. Angular is not throwing any errors. Here is the RouteComponent along with its view: im ...

Having trouble resolving TypeScript TS2322 error with Context API + useState hook in your React App?

Currently, I am working on a React Typescript project that utilizes the Context API to pass down a useState hook. export const AppContext = React.createContext(null); function App() { const [value, setValue] = React.useState(3); return ( <Ap ...