Typescript-Compiler, der Typ mit Generika ableitet
Ich versuche eine generische isEventOfTypeFunktion zu erreichen . An mehreren Stellen werden Ereignisse aus einer X-State-Statemaschine definiert (siehe Maschine1Events, Maschine2Events). Bei der Verarbeitung von Ereignissen können x-Zustände nur ein Maschine1Eventsoder Maschine2Eventsangeben, aber nicht genau sagen, welches Ereignis verarbeitet wird.
Ich benötige daher eine Methode, um zu überprüfen, ob das Ereignis von einem Typ ist, den ich erwarte. Zum Beispiel, dass das Ereignis 'CHANGE' bereitgestellt wird.
Dieses Beispiel ist voll funktionsfähig, aber ich verstehe nicht, warum innerhalb der fWithoutGenericFunktion die Typen nicht abgeleitet werden können.
export type Event<TType, TData = unknown> = { type: TType } & TData;
export type Value<TType> = { value: TType };
type Maschine1Events = Event<'INC'> | Event<'DEC'> | Event<'CHANGE', Value<number>>;
type Maschine2Events = Event<'INC', Value<number> | Event<'SEND_MESSAGE', Value<string>>;
type EventTypes<T extends Event<unknown>> = T['type'];
type EventOfType<T extends Event<unknown>, U extends EventTypes<T> = EventTypes<T>> = Extract<T, { type: U }>;
function isEventOfType<T extends Event<unknown>, U extends EventTypes<T> = EventTypes<T>>(
event: T,
type: U
): event is EventOfType<T, U> {
return event.type === type;
}
function fWithGenerics(event: Maschine1Events) {
if (isEventOfType<Maschine1Events, 'CHANGE'>(event, 'CHANGE')) {
const a: Event<'CHANGE', Value<number>> = event;
}
}
function fWithOutGenerics(event: Maschine2Events) {
if (isEventOfType(event, 'SEND_MESSAGE')) {
const a: Event<'SEND_MESSAGE', Value<string>> = event; //Why can't this be infered
}
}
Spielplatz Link zum Code
Antworten
Ich würde gerne isEventOfType()folgende Unterschrift geben:
function isEventOfType<E extends { type: string }, T extends E['type']>(
event: E,
type: T
): event is Extract<E, { type: T }> {
return event.type === type;
}
Ich habe die Parameter etwas vereinfacht und die generischen Parameterstandards für den zweiten Parameter entfernt. Ich weiß nicht, worum es bei diesen ging, aber wenn Sie sie nicht brauchen, sind sie wahrscheinlich nur eine Ablenkung.
Die große Veränderung ist , dass die EArt des eventParameters nun gezwungen zu {type: string}statt {type: unknown}. Das stringgibt der Compiler einen Hinweis ein herzuleiten Stringliteral Typ für den Typ Tdes typeParameters (siehe microsoft / Typoskript # 10676 Einzelheiten über darüber , wie Inferenz von wörtlichen Typen geschieht).
Jetzt funktioniert der Code wie erwartet, denke ich:
function m1(event: Maschine1Events) {
if (isEventOfType(event, 'CHANGE')) {
event.value.toFixed(2); // okay
} else {
event // {type: "INC"} | {type: "DEC"}
}
}
function m2(event: Maschine2Events) {
if (isEventOfType(event, 'SEND_MESSAGE')) {
event.value.toUpperCase(); // okay
} else {
event.value.toFixed(2); // okay
}
}
Spielplatz Link zum Code