访问联合类型属性的惯用法

时间:2016-11-29 19:46:33

标签: flowtype union-types

访问union中合并的其中一种类型中可能缺少的union类型属性的惯用方法是什么?

type DataColumn = {
  value: number;
};

type CalculatedColumn = {
  calculation: string;
};

type Column = DataColumn | CalculatedColumn;

function getValue(c: Column) {
  return c.value || c.calculation;
}

Flow typecheck会导致以下错误:

13:   return c.value || c.calculation;
                          ^ property `calculation`. Property not found in
13:   return c.value || c.calculation;
                        ^ object type

@dfkaye在Twitter上指出,如果“默认”情况引发错误,则可行:

function e() {
  throw new Error('foo');
}

function getValue(c: Column) {
  return c.value || c.calculation || e();
}

有人可以解释一下:

  1. 为什么会这样?这是故意还是副作用?
  2. 为什么有必要?列类型始终为valuecalculation,因此不应出现错误情况。
  3. 是否有更好,更惯用的方式?
  4. 这是一种安全的方法,还是将来可能会破裂?
  5. PS:似乎在TypeScript it can be done中使用类型断言。

2 个答案:

答案 0 :(得分:3)

惯用法是使用disjoint unions。这传递没有错误:

type DataColumn = {
  kind: 'data';
  value: number;
};

type CalculatedColumn = {
  kind: 'calculated';
  calculation: string;
};

type Column = DataColumn | CalculatedColumn;

function e() {
  throw new Error('foo');
}

function getValue(c: Column) {
  return c.kind === 'data' ? c.value : c.calculation;
}

getValue({kind: 'data', value: 123});
getValue({kind: 'calculated', calculation: 'foo'});

我真的不确定为什么你描述的案例不起作用。我无法想出任何不合理的理由。但不相交的工会肯定有效。

答案 1 :(得分:2)

  

为什么会这样?这是故意还是副作用?

它很可能是一个错误,Flow简单忽略所有分支但最后:

function getValue(c: Column) {
  return c.value || c.calculation || undefined;
}
  

为什么有必要?列类型始终是值或计算,因此错误情况永远不会发生

这是你错的地方。如果值的类型为{ value: number },则表示它可以包含任何类型的任何其他属性,包括类型为calculation的{​​{1}},或者可能属于其他类型。

  

是否有更好,更惯用的方式?

是的,请参阅Nat Mote的回答

  

这是一种安全的方法,还是将来可能会破裂?

原则上它不安全,所以它很有可能在未来破裂

  

在TypeScript中似乎可以使用类型断言来完成。

你可以在Flow中做同样的事情,但它不安全:

string

另外你不应该忘记数字和字符串可能是假的。