Alexander Myshov
Alexander Myshov

Reputation: 3101

How to refine types in function that takes union of arrays?

There is some function that delegate job to other functions depending of the type of the input array. How can I point out that particular array has to be processed by particular function?

I've been thinking about it and searching for several hours, but couldn't find a solution.

type nameType = {
  name: string,
}

type surnameType = {
  surname: string
};

type inputType = nameType[] | surnameType[];

function processSurnames(suranmes: surnameType[]) {
  let result = {};
  // do something with surnames
  return result;
}

function processNames(names: nameType[]) {
  let result = {};
  // do something with names
  return result;
}

function process(input: inputType) {
  if (typeof input[0].name === 'string') { // <--- this refinement doesn't work
    return processNames(input);
  } else {
    return processSurnames(input);
  }
}

the code on flow.org/try

Upvotes: 1

Views: 184

Answers (2)

James Kerr
James Kerr

Reputation: 326

It is not possible to refine based on the types of items in an array.

This is because array access is unsafe -- it is always possible for array access to return undefined. Refinements can be made with anything other than an array.

I've rewritten your example wrapping the arrays in objects and refining based the "type" property.

// ...

type Names = { type: "names", list: nameType[] }
type Surnames = { type: "surnames", list: surnameType[] }

// ...

export function process(input: Names | Surnames) {
  if (input.type === "names") {
    return processNames(input.list)
  } else {
    return processSurnames(input.list)
  }
}

Here is the try flow link.

Unfortunate :(

Upvotes: 1

Konrad
Konrad

Reputation: 24661

Have you tried instanceof? What does it mean doesnt't work? Have you checked what typeof input[0].name returns?

Upvotes: 0

Related Questions