Green Mtn
Green Mtn

Reputation: 447

How to type a constant with string-defined functions?

Let's say I have this TypeScript code:

enum EVENT {
  FIRST_EVENT = "game:first_encounter",
}

const EventHandler: keyof typeof EVENT = {
    [EVENT.FIRST_EVENT]: (data: any) => {
        console.log(`Hello there, ${data.blue_player}`);
    }
}

const data = { blue_player: 'Blue McBlue', event: EVENT.FIRST_EVENT}
const eventName: EVENT = data.event;

EventHandler[eventName](data);

I have an error with EventHandler near the top.

Type '{ "game:first_encounter": (data: any) => void; }' is not assignable to type '"FIRST_EVENT"'

I also have an error of with eventName on the last line with:

Element implicitly has an 'any' type because index expression is not of type 'number'

https://www.typescriptlang.org/play?#code/KYOwrgtgBAogajAcgFSgbwFBSgMQJIBKAysgPrxKoC8UARAOYCGEwAXAGYCWATgM4AupUAGMA9mBD9g3WgBoMAXwwYxIAbABuofgAlGIACYAbaaygBrYAE9R7KPysAHYLc3aoNTNmwBtCigA6fGIyf2QAXTMACgNGfkYzfSsASg8APnQsb2zVXlETAKNReiiAAx1gIyL7AAtpYFkoABI0WPiAgCMjMGBSRyNGK2kFUuSAbizsJSUVUTV+KDbGD3QoLp6+gaHuMwByACFu4CgAWWFDnt3G4C1JMzCgwhJyBBQlXIWb7URmNlhX6iLOKMAJfSQTDAwW66fTGaQ+MH8H4scIxYHjIA

See what I mean? How can I correctly type this?

Upvotes: 2

Views: 52

Answers (1)

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276446

Let's start typing EventHandler and figure this out.

First of all it's an object:

type EventHandlerType = {};

It has keys that are EVENTs

// Create a mapped type mapping events to anything
type EventHandlerType = { [e in EVENT]: any }

Every value is a function that takes a data parameter and returns void

// Create a mapped type mapping events to anything
type EventHandlerType = { [e in EVENT]: (data: any) => void };

Which should work in your code:

const EventHandler: { [key in EVENT]: (data: any) => void } = {
    [EVENT.FIRST_EVENT]: (data: any) => {
        console.log(`Hello there, ${data.blue_player}`);
    }
}

This is made simpler with the built in utility type Record which exists for these cases:


const EventHandler: Record<EVENT, (data: any) => void> = {
    [EVENT.FIRST_EVENT]: (data: any) => {
        console.log(`Hello there, ${data.blue_player}`);
    }
}

See mapped types in the docs for more examples and a drill down.

Upvotes: 2

Related Questions