คอมไพเลอร์ typescript infering type กับ generics
ฉันพยายามบรรลุisEventOfTypeฟังก์ชันทั่วไป ในสถานที่หลายเหตุการณ์ที่เกิดขึ้นจาก StateMachine x รัฐมีการกำหนด (ดูMaschine1Events, Maschine2Events) เมื่อประมวลผลเหตุการณ์ x-state สามารถระบุได้เพียงMaschine1EventsหรือMaschine2Eventsแต่ไม่สามารถบอกได้ว่าเหตุการณ์ใดถูกประมวลผล
ฉันจึงต้องการวิธีตรวจสอบว่าเหตุการณ์เป็นประเภทที่ฉันคาดหวังหรือไม่ ตัวอย่างเช่นเหตุการณ์ "CHANGE" มีให้
ตัวอย่างนี้ใช้งานได้อย่างสมบูรณ์ แต่สิ่งที่ฉันไม่เข้าใจคือเหตุใดในfWithoutGenericฟังก์ชันจึงไม่สามารถอนุมานประเภทได้
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
}
}
ลิงก์สนามเด็กเล่นไปยังรหัส
คำตอบ
ฉันมีแนวโน้มที่จะให้isEventOfType()ลายเซ็นต่อไปนี้:
function isEventOfType<E extends { type: string }, T extends E['type']>(
event: E,
type: T
): event is Extract<E, { type: T }> {
return event.type === type;
}
ฉันทำให้พารามิเตอร์ง่ายขึ้นเล็กน้อยและลบค่าเริ่มต้นของพารามิเตอร์ทั่วไปสำหรับพารามิเตอร์ที่สอง ฉันไม่รู้ว่าประเด็นเหล่านั้นคืออะไร แต่ถ้าคุณไม่ต้องการมันก็อาจเป็นเพียงสิ่งที่ทำให้ไขว้เขว
การเปลี่ยนแปลงใหญ่ที่นี่เป็นที่Eประเภทของeventพารามิเตอร์ในขณะนี้มีข้อ จำกัดในการแทน{type: string} ให้เรียบเรียงคำใบ้ที่จะอนุมานชนิดสตริงตัวอักษรสำหรับชนิดของพารามิเตอร์ (ดูMicrosoft / typescript # 10676สำหรับรายละเอียดเกี่ยวกับเกี่ยวกับการอนุมานชนิดที่แท้จริงเกิดขึ้น){type: unknown}stringTtype
ตอนนี้รหัสทำงานได้ตามที่คุณคาดหวังฉันคิดว่า:
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
}
}
ลิงก์สนามเด็กเล่นไปยังรหัส