In the TypeScript documentation site
https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
it has sample code as follows:
type EventConfig<Events extends { kind: string }> = {
[E in Events as E["kind"]]: (event: E) => void;
}
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };
type Config = EventConfig<SquareEvent | CircleEvent>
what's the meaning of E in Events
?
Please help me! Thank you very much!
CodePudding user response:
The in
keyword is used for a few different things in TypeScript, but this particular one is using in
to select each individual member of the union type Events
in order to map it.
EventConfig
is a mapped type that uses the members of the union to define the properties of an object type. (We know that because of the form it's in, { KeyType: ValueType }
.) E in Events
defines the E
identifier, saying "for each union member, use E
to refer to that individual member's type" for the purposes of defining each property in the object type being defined. Given the example EventConfig<SquareEvent | CircleEvent>
, that means that E
is each individual member of the union (SquareEvent
and, separately, CircleEvent
) during the mapping operation (in contrast, Events
is the union of those members). It's almost like a loop through the union members (though it isn't a loop).
After E in Events
, the as E["kind"]
part of the property key expression says "And from E
, take the type of the kind
property as the property key."
With that in mind, let's look at the overall property definition part of that mapped type:
{
[E in Events as E["kind"]]: (event: E) => void;
}
For EventConfig<SquareEvent | CircleEvent>
, that will be evaluated with E
being SquareEvent
and also E
being CircleEvent
, where each of them defines one property in the resulting object type. Let's expand that, replacing E
with each of the union members:
{
[SquareEvent["kind"]]: (event: SquareEvent) => void;
[CircleEvent["kind"]]: (event: CircleEvent) => void;
}
we can go further, though, because we can resolve the type of SquareEvent["kind"]
to the string literal type "square"
and CircleEvent["kind"]
to "circle"
, giving us:
{
square: (event: SquareEvent) => void;
circle: (event: CircleEvent) => void;
}