打字稿 - 具有联合类型的交集运算符

时间:2021-04-27 16:11:25

标签: typescript

这是一个事件发射器的设计:

n

设计有效,但有两件事我不明白:

  1. 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

  2. 为什么我们需要带有 string &K 方法的泛型 onemit 参数的类型不能简单地为 eventKey

非常感谢。

1 个答案:

答案 0 :(得分:2)

<块引用>

EventKey:为什么要在这里加一个字符串&?

交集 string & ... 用于确保只有实际类型为 string 的键才能用于定义 EventKey 类型。

即使 EventMap 定义为 Record<string,any>,您仍然可以为其分配具有非字符串属性的对象:

const a: EventMap = {
  foo: 'bar',
  100: 'baz', // whoops, number property
}

为什么?因为对象可以有 excess properties

因此在这种情况下,对于非 string & keyof T 类型的流氓属性,never 将导致 string

<块引用>

eventKey 参数的类型不能简单地为 keyof T 吗?

这是为了允许定义为联合类型的键,它确实扩展了 string(另见 this answer):

type EnumK = 'alpha' | 'beta'
type MyObject = {[P in EnumK]: string }

const obj: SomeObj = {
  alpha: 'foo',
  beta: 'bar'
}

这里obj的键类型是string扩展,即字符串文字类型alpha和{{1}的联合}.因此,通过使用 beta,您可以捕获这种关系并确保类型索引 K extends ... 中的类型安全。