首页 > 解决方案 > 键值对的 TypeScript 类型别名

问题描述

我有一个界面:

export interface PostEventTypeMap {
  changePrice: number;
  changeQuantity: number;
  signalConnected: boolean;
  signalDisconnected: boolean;
}

我如何定义一个类型别名,如:

type PostEvent = {
  type: keyof PostEventTypeMap,
  value: **Value based on key value and PostEventTypeMap**
};

我不能使 postEvent 属性通用:

PostBoxService {
  get postEvent(): Observable<PostEvent> {
    return getOrCreateValue(this, "postEvent", () => new BehaviorSubject(null));
  }
}

服务用例:

postBoxService
  .postEvent
  .subscribe(event => {
    if (!event)
      return;

    switch (event.type) {
      case "changePrice":
        this.changePrice(event.value);
        break;
      case "changeQuantity":
        this.changeQuantity(event.value);
        break;
    }
  });

标签: typescript

解决方案


因为您有有限数量的可能性,并且由于该type值始终是文字类型,所以您可以将其设为可区分的 union。一种方法是将属性映射PostEventTypeMap到所需的联合成员,然后立即查找这些属性以获取联合:

type ObjToTypeValueUnion<T extends object> = 
  { [K in keyof T]-?: { type: K, value: T[K] } }[keyof T]

type PostEvent = ObjToTypeValueUnion<PostEventTypeMap>;
/* type PostEvent = {
    type: "changePrice";
    value: number;
} | {
    type: "changeQuantity";
    value: number;
} | {
    type: "signalConnected";
    value: boolean;
} | {
    type: "signalDisconnected";
    value: boolean;
} */

您可以验证这是否适合您的用例:

declare function changePrice(x: number): void;
declare function changeQuantity(x: number): void;
((event?: PostEvent) => {
  if (!event)
    return;

  switch (event.type) {
    case "changePrice":
      changePrice(event.value);
      break;
    case "changeQuantity":
      changeQuantity(event.value);
      break;
  }
});

Playground 代码链接


推荐阅读