【问题标题】:TypeScript type alias for key-value pair键值对的 TypeScript 类型别名
【发布时间】:2020-10-20 22:29:06
【问题描述】:

我有一个界面:

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


    【解决方案1】:

    因为您有有限数量的可能性,并且由于type 值将始终是文字类型,所以您可以将其设为discriminated union。一种方法是将mapPostEventTypeMap 属性传递给你想要的联合成员,然后立即look up 这些属性得到联合:

    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 link to code

    【讨论】:

      【解决方案2】:

      您可能需要将PostEvent 类型设为泛型,如:

      export interface PostEventTypeMap {
        changePrice: number;
        changeQuantity: number;
        signalConnected: boolean;
        signalDisconnected: boolean;
      }
      
      type PostEvent<T extends keyof PostEventTypeMap> = {
        type: T,
        value: PostEventTypeMap[T]
      };
      
      const validChangePrice: PostEvent<'changePrice'> = {
        type: 'changePrice',
        value: 1
      }
      
      const invalidChangePrice: PostEvent<'changePrice'> = {
        type: 'changePrice',
        value: true // Compile error TS2322: Type 'true' is not assignable to type 'number'.
      }
      
      

      【讨论】:

      • 谢谢,但我不想让它泛泛而谈。因为我使用这种类型作为 getter 属性的返回类型
      猜你喜欢
      • 2020-09-03
      • 2016-01-13
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 2019-03-02
      • 2017-08-08
      • 2020-10-12
      相关资源
      最近更新 更多