如何使用附加属性扩展联合类型?

时间:2018-04-20 18:30:49

标签: flowtype

我正在使用disjoint union types来表示事件,recommended for Redux-like actions也是如此。通常这很好用,但在我的应用程序的某些部分,事件有一个额外的时间戳字段。如何在不重复某事的情况下注释带时间戳的事件的类型?

我尝试使用intersection types合并其他必需属性,但以下操作失败:

/* @flow */

export type EvtA = {type: 'A', prop1: string};
export type EvtB = {type: 'B', prop2: string};

export type Event =
  | EvtA
  | EvtB;

type Timestamped = { timestamp: number };

type TSEvent = Event & Timestamped;
function show(event : TSEvent) {
  console.log(event.timestamp);
//  let event = ((e: any): Event);
  if (event.type === 'A') {
    console.log(event.prop1);
  }
}

错误(在http://flow.org/try上):

 function show(event : TSEvent) {
                          ^ all branches are incompatible: Either property `prop1` is missing in `EvtB` [1] but exists in `EvtA` [2]. Or property `prop1` is missing in `Timestamped` [3] but exists in `EvtA` [2]. Or property `prop2` is missing in `EvtA` [1] but exists in `EvtB` [4]. Or property `prop2` is missing in `Timestamped` [3] but exists in `EvtB` [4].
References:
12: type TSEvent = Event & Timestamped;
                   ^ [1]
7:   | EvtA       ^ [2]
12: type TSEvent = Event & Timestamped;
                           ^ [3]
8:   | EvtB;
       ^ [4]
17:     console.log(event.prop1);
                    ^ Cannot get `event.prop1` because: Either property `prop1` is missing in `EvtB` [1]. Or property `prop1` is missing in `Timestamped` [2].
References:
12: type TSEvent = Event & Timestamped;
                   ^ [1]
12: type TSEvent = Event & Timestamped;
                           ^ [2]

评论出的类型转换是我目前的hacky解决方法。

(是的,也许更干净的方法可能是type LogEntry = { event: Event, timestamp: number },但这需要更改很多其他代码。)

1 个答案:

答案 0 :(得分:1)

您可能正在寻找的是物品传播:

Try

/* @flow */

export type EvtA = {type: 'A', prop1: string};
export type EvtB = {type: 'B', prop2: string};

export type Event =
  | EvtA
  | EvtB;

type Timestamped = {timestamp: number };

type TSEventA = {
  ...EvtA,
  ...Timestamped,
};

// TSEventA now has type:
// {prop1?: mixed, timestamp?: mixed, type?: mixed}

function show(event : TSEventA) {
  console.log(event.timestamp);
  //  let event = ((e: any): Event);
  if (event.type === 'A') {
    console.log(event.prop1);
  }
}

您可以通过传播exact objects

来保留所有类型信息

Try

/* @flow */

export type EvtA = {|type: 'A', prop1: string|};
export type EvtB = {|type: 'B', prop2: string|};

export type Event =
  | EvtA
  | EvtB;

type Timestamped = {|timestamp: number|};

type TSEvent = {
  ...Event,
  ...Timestamped
};

// TSEvent now has union type:
// {prop2: string, timestamp: number, type: "B"}
// | {prop1: string, timestamp: number, type: "A"}

function show(event : TSEvent) {
  console.log(event.timestamp);
  if (event.type === 'A') {
    console.log('A', event.prop1);
  } else if (event.type === 'B') {
    console.log('B', event.prop2);
  }
}