4

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

type DataColumn = {
  value: number;
};

type CalculatedColumn = {
  calculation: string;
};

type Column = DataColumn | CalculatedColumn;

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

类型检查导致以下错误:

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. 为什么有必要?列类型始终为valueor calculation,因此永远不会发生错误情况。
  3. 有没有更好、更惯用的方法?
  4. 这是一种安全的方法,还是将来可能会中断?

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

4

2 回答 2

4

惯用的方法是使用不相交的联合。这通过没有错误:

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'});

我实际上不确定为什么您描述的案例不起作用。我想不出任何理由它会不健全。但是不相交的工会肯定会起作用。

于 2016-11-29T22:06:10.707 回答
2

为什么它有效?是故意的,还是副作用?

这很可能是一个错误,Flow simple 会忽略所有分支,但最后一个:

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

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

这是你错的地方。如果 value 具有类型{ value: number },则意味着它可以具有任何类型的任何其他属性,包括calculation类型string或可能是其他类型。

有没有更好、更惯用的方法?

是的,请参阅 Nat Mote 的回答

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

原则上是不安全的,所以以后很可能会坏掉

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

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

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

此外,您不应忘记数字和字符串可能是错误的。

于 2016-11-30T10:53:33.487 回答