我試圖定義一個強型別的事件發射器,我最想要的是從傳遞給addEventHandler函式的字串中推斷出回呼的事件型別。
但到目前為止我已經失敗了,我想出的是從回呼推斷事件型別,而不是相反。
這是一個示例(帶有小提琴):
interface NumberEvent {
type: 'NumberEvent';
num: number;
}
interface StringEvent {
type: 'StringEvent';
str: string;
}
type AnyEvent = NumberEvent | StringEvent;
const addEventHandler = <ET extends AnyEvent>(type: ET['type'], handler: ((event: ET) => void)) => {
console.log(`added event handler for ${type}`);
}
addEventHandler('NumberEvent', (event: NumberEvent) => {
// this is cool
});
addEventHandler('NumberEvent', (event: StringEvent) => {
// this doesn't type check, good
});
addEventHandler('type does not exist', (x: any) => {
// why no type error?
});
我不明白為什么最后一行要進行型別檢查,因為沒有AnyEventwith type 的實體'type does not exist'。
你能想到一個更好的方法來解決這個問題嗎?
uj5u.com熱心網友回復:
您可以通過addEventHandler在事件型別而不是事件物件上進行泛型來實作這一點。
const addEventHandler = <ET extends AnyEvent['type']>(
type: ET,
handler: ((event: Extract<AnyEvent, { type: ET }>) => void)
) => {
console.log(`added event handler for ${type}`);
}
你也可以使用AnyEvent & { type: ET }代替Extract<AnyEvent & { type: ET }
您的型別不能阻止最后一種情況的原因ET是因為推斷為any. any["type"]is still any,所以它會允許任何字串。
上面的版本仍然不會阻止某人這樣做:
addEventHandler<any>('type does not exist', (x: any) => {
// explicitly providing <any>
});
您可以通過使用<anything> & anyis的事實來防止這種情況發生any,但我個人不會打擾。any除非故意打破你的型別,否則沒有人可能會在這里提供。通過any檢查,您還可以回傳到您的通用:
type NotAny<T> = 0 extends (1 & T) ? never : T;
const addEventHandler = <ET extends AnyEvent>(type: NotAny<ET["type"]>, handler: ((event: ET) => void)) => {
console.log(`added event handler for ${type}`);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/401136.html
上一篇:通過反射找出類是否實作了介面
