[英]Typescript - intersection operator with union type
這是一個事件發射器的設計:
type EventMap = Record<string, any>;
type EventKey<T extends EventMap> = string & keyof T;
type EventReceiver<T> = (params: T) => void;
interface Emitter<T extends EventMap> {
on<K extends EventKey<T>>
(eventKey: K, fn: EventReceiver<T[K]>): void;
emit<K extends EventKey<T>>
(eventKey: K, params: T[K]): void;
}
// example usage
const emitter = eventEmitter<{
data: Buffer | string;
end: undefined;
}>();
// OK!
emitter.on('data', (x: string) => {});
// Error! 'string' is not assignable to 'number'
emitter.on('data', (x: number) => {});
設計有效,但有兩件事我不明白:
EventKey
:為什么要在此處添加string &
?
為什么我們需要 generics K
和on
和emit
方法, eventKey
參數的類型不能簡單地是keyof T
嗎?
提前謝謝了。
EventKey:為什么要在此處添加字符串&?
交集string &...
用於確保只有實際上是string
類型的鍵才能用於定義EventKey
類型。
即使EventMap
被定義為Record<string,any>
您仍然可以為其分配具有非字符串屬性的 object:
const a: EventMap = {
foo: 'bar',
100: 'baz', // whoops, number property
}
為什么? 因為對象可以有多余的屬性。
因此,在這種情況下, string & keyof T
將導致never
用於非string
類型的流氓屬性。
eventKey 參數的類型不能簡單地是 keyof T 嗎?
這是為了允許將鍵定義為聯合類型,它們會擴展string
(另請參閱此答案):
type EnumK = 'alpha' | 'beta'
type MyObject = {[P in EnumK]: string }
const obj: SomeObj = {
alpha: 'foo',
beta: 'bar'
}
這里obj
的鍵的類型是string
的擴展,即字符串文字類型alpha
和beta
之間的並集。 因此,通過使用K extends...
您可以捕獲這種關系並確保類型索引T[K]
中的類型安全。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.