FLOW: how to make Flow work with callback for Array.prototype.find()

Viewed 1009

Guys I'm new to Flow.

I have this code

type importItem = {
  name: string,
  groupRank: number,
  rank: number,
  node: Object,
};
function findTargetImportItem(importedItems: Array<importItem>, outOfOrderItem: importItem) : importItem {

return importedItems.find((importedItem: importItem) => importedItem.rank > outOfOrderItem.rank);}

I got this error

Cannot return importedItems.find(...) because undefined [1] is incompatible with importItem [2].

     src/rules/import-order.js
 [2]  74│ function findTargetImportItem(importedItems: Array<importItem>, outOfOrderItem: importItem) : importItem {
      75│   /**
      76│      * Return the import where the unordered imports will be moving towards
      77│      */
      78│   return importedItems.find((importedItem: importItem) => importedItem.rank > outOfOrderItem.rank);
      79│ }
      80│
      81│ function hasTrailingSpace(sourceCode, node) {

     /private/tmp/flow/flowlib_21840530/core.js
 [1] 244│     find(callbackfn: (value: T, index: number, array: Array<T>) => any, thisArg?: any): T | void;

I don't know how to make Flow know that the stuff returned by the find helper function is an importItem type.

Can you guys help me with this

1 Answers

The flow compiler is correct. It knows that the value returned by find() can be undefined.

If none of the items in the array satisfy the condition in the callback you've passed, the return value will be undefined. Either change your return type for findTargetImportItem() to void | importItem or assign the return value of find() to a temporary variable and return some default value of type importItem if the temporary variable is undefined.

Solution 1

function findTargetImportItem(importedItems: Array<importItem>, outOfOrderItem: importItem) : void | importItem {
  /**
    * Return the import where the unordered imports will be moving towards
    */
  return importedItems.find((importedItem: importItem) => importedItem.rank > outOfOrderItem.rank);
}

Solution 2

const defaultImportItem: importItem = ...;

function findTargetImportItem(importedItems: Array<importItem>, outOfOrderItem: importItem) : importItem {
  /**
    * Return the import where the unordered imports will be moving towards
    */
  const importedItem = importedItems.find((importedItem: importItem) => importedItem.rank > outOfOrderItem.rank);

  return importedItem === undefined
    ? defaultImportItem
    : importedItem;
}
Related