Laurenz1606
Laurenz1606

Reputation: 98

TypeScript dynamic Function definition based on functions argument

is it posible to change the type of something based on the value of an argument passed to a function. I need this kind of type for an event emiter with callback. Example:

interface IUser {
  name: string
}

type CallBack = /* the Type for the Callback that should be dynamic */

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

//for event2 the type CallBack should be (email: string, password: string) => any
use("event2", (email, password) => { /* check that event12is used, so add 2 argument to the callback type */ })

so is there a way to detect which event is used and apply the right type to the callback?

Upvotes: 1

Views: 2085

Answers (2)

MaximeCrp
MaximeCrp

Reputation: 31

You could use types like this:

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)

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249466

The simplest way to do it is with overloads.


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

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

//for event2 the type CallBack should be (email: string, password: string) => any
use("event2", (email, password) => { /* check that event12is used, so add 2 argument to the callback type */ })

Playground Link

If you have a more complex scenario, such as already having the callbacks in another type, or more complicated conditions, you might consider tuples in rest parameters and conditional types. But from your question, that would be overkill.

Upvotes: 3

Related Questions