Search code examples
typescriptmapped-types

Assign function signature to type in TypeScript


Let's say I have a function:

function registerEvent(event: Event, handler: HandlerSignature);

and these are the respective types:

enum Event {
  EventOne,
  EventTwo
}

type HandlerSignature = (...args: any[]) => void;

Now every event could have a different function signature, for example:

function handler1(foo: number, bar: string);
function handler2(foo: string);

What I'd like to achieve is that I can call the registerEvent function, specify the first arg (event) and let TypeScript detect which signature corresponds with this event, i.e. for intellisense and to prevent users from assigning wrong signatures to an event.

I thought about creating a map where I assign the different signatures to the enum values, but I can't really use that as type, can I? Even if I used a mapped type I'd have to create a variable to assign all the events.


Solution

  • I'd lean toward function overloading:

    enum Events {
      EventOne,
      EventTwo
    }
    
    type HandlerSignature = (...args: any[]) => void;
    
    function registerEvent(event: Events.EventOne, handler: (foo: number, bar: string) => void): void;
    function registerEvent(event: Events.EventTwo, handler: (foo: number) => void): void;
    function registerEvent(event: Events, handler: HandlerSignature):void {
        // ...implementation
    }
    
    function handler1(foo: number, bar: string) {}
    function handler2(foo: string) {}
    
    registerEvent(Events.EventOne, handler1); // Works
    registerEvent(Events.EventOne, handler2); // Error as desired, wrong type for callback
    

    Playground link

    (Note I changed Event to Events; Event is a pre-existing global and type in the browser environment and Node.js)