Ошибка создания типов потока для, казалось бы, не связанных типов - PullRequest
0 голосов
/ 02 мая 2018

У меня есть следующий flow код ( доступно здесь ):

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>

Кроме того, если я заменил уменьшение на цикл for , это сработает:

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 голосов
/ 03 мая 2018

Я думаю, вы можете принять массив из InternalSquare или SquareState:

( Попробуйте )

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>). Это может быть даже PR-достойно.

Интересно, что расширение массива позволяет потоку понимать тип как Array<InternalSquare | SquareState>:

( Попробуйте )

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

Я бы рискнул предположить, что он на самом деле оценивает каждую из возможностей в этом случае и находит, что обе возможности работают. Общая спекуляция, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...