1

I'm wondering if it's possible to create dynamic type that would replace two params, such as in on: (eventName: EventName, callback: (data: any) => void) => void with something closer to this on: (DynamicParams<EventName>) => void, so it could extract callback's type from a predefined set and use it instead of any type.

I think it would be easier to explain with some code.

Say, I have set of different types of events:

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

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

type EventName = ArrayElement<typeof events>

and a function that runs only when a specific notification has been emitted;

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

But I want to be able to use this function with callback that accepts different parameter types, without checking for the type manually and without any casting, for example:

on('loaded', (list: Entry[]) => {
  // do something with loaded array of elements;
}

on('changed', (index: number) => {
  // do something with index of a changed entry;
}

Is there a way to create a mapped type that would accept EventName and return a specific type to a given event?

Something like that:

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

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

Assume, I would need to replace event object and create a type in its place, instead:

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

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

But I'm not sure how to extract name values (not types of the values).

2
  • 1
    So this? You may face some type issues when implementing the function (the body) with these kinds of things, though. Commented Nov 2, 2022 at 20:07
  • @caTS, Thank you. I think it would work perfectly for now. Commented Nov 2, 2022 at 20:34

2 Answers 2

1

If you define a map of event names to their data type:

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

You can make on generic:

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

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

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

Playground

Sign up to request clarification or add additional context in comments.

Comments

1

There are two ways to make this work:

Using call signatures:

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

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

Or 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) {
    // Choose how to register the event here...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.