流类型在看似无关的类型上抛出错误

时间:2018-05-02 01:30:15

标签: javascript flowtype

我有以下flow代码(available here):

type SquareState = {
  value: number,
};

type InternalSquare = {
  value: number | null,
};

export function getMax(squares: Array<InternalSquare> | Array<SquareState>): number {
   return squares.reduce(function(a : number, b : InternalSquare | SquareState): number {
    if (b.value === null) {
      return a;
    } else {
      return Math.max(a, b.value);
    }
  }, 0);
}

产生此错误:

 9: export function getMax(squares: Array<InternalSquare> | Array<SquareState>): number {
                                                             ^ number [1] is incompatible with null [2] in property `value`.
   References:
   2:   value: number,
               ^ [1]
   6:   value: number | null,
                        ^ [2]

据我了解,应该没有错误,因为有防范null。代码可以正常使用:

export function getMax(squares: Array<SquareState>):  number

export function getMax(squares: Array<InternalSquare>): number

但不是Array<SquareState> | Array<InternalSquare>

此外,如果我replace the reduce with a for loop,它可以运作:

export function getMax(squares: Array<InternalSquare> | Array<SquareState>): number {
  var max = 0;
  for(var i = 0 ; i < squares.length ; i ++) {
     if (squares[i].value === null) {
       continue;
     } else {
       max = Math.max(max, squares[i].value);
     }
  }
  return max;
}

我错过了什么?

1 个答案:

答案 0 :(得分:2)

我想你可能想要接受InternalSquareSquareState的数组:

Try

type SquareState = {
  value: number,
};

type InternalSquare = {
  value: number | null,
};

export function getMax(squares: Array<InternalSquare | SquareState>): number {
    return squares.reduce(function(a : number, b : InternalSquare | SquareState): number {
      if (b.value === null) {
        return a;
      } else {
        return Math.max(a, b.value);
      }
    }, 0);
}

似乎流不会意识到减少两个数组(Array<A> | Array<B>)的并集等同于减少两种类型的并集数组(Array<A | B>)。这甚至可能是有价值的。

有趣的是,传播数组允许流程将类型理解为Array<InternalSquare | SquareState>

Try

type SquareState = {
  value: number,
};

type InternalSquare = {
  value: number | null,
};

export function getMax(squares: Array<InternalSquare> | Array<SquareState>): number {
    const afterSpread = [...squares]
    return afterSpread.reduce(function(a : number, b : InternalSquare | SquareState): number {
      if (b.value === null) {
        return a;
      } else {
        return Math.max(a, b.value);
      }
    }, 0);
}

更有趣的是,如果您将其中一个数组(但不是两个!)更改为$ ReadOnlyArray,它也会理解这里发生了什么:

type SquareState = {
  value: number,
};

type InternalSquare = {
  value: number | null,
};

export function getMax(squares: $ReadOnlyArray<InternalSquare> | Array<SquareState>): number {
    return squares.reduce(function(a : number, b : InternalSquare | SquareState): number {
      if (b.value === null) {
        return a;
      } else {
        return Math.max(a, b.value);
      }
    }, 0);
}

我猜测它实际上是在评估这种情况下的每种可能性,并发现两种可能性都有效。但总的猜测。