There are times when you may want a function to be able to take different types of parameters. A little bit like union types in TypeScript. Let's see how it can be done using Flow.

Creating a Function That Takes a Parameter of Multiple Types

flow illustration for: Creating a Function That Takes a Parameter of Multiple Types

It's just a matter of listing the possible types, delimited by a <^>|<^>:

				
					
function capitalize(

  // `capitalize` can take a string or an array of strings.

  words: string | Array&lt;string&gt;,

  // `capitalize` will return an array of strings either way.

): Array&lt;string&gt; {

  // At this point, Flow does not know if `words` is a string or an array,

  // so properties or methods specific to those types,

  // such as `map` and `toUpperCase`, cannot be accessed.

  // However, properties or methods that are shared by both, such as `length`, can be accessed.

  if (!Array.isArray(words)) {

    // Flow now knows that `words` is a string, so we can use string methods.

    return [words.toUpperCase()];

  }

  // Flow now knows that `words` is an array, so we can use array methods.

  return words.map(word =&gt; word.toUpperCase());

}

				
			

Helping Flow Determine the Type

The above example used Array.isArray to determine the type of words, but there are other ways Flow can do this:

				
					
// Through truthiness

function cube(val: number | void): number {

  // If `val` is falsy, it must be undefined (or 0).

  if (!val) {

    return 0;

  }

  // Otherwise, `val` must be a number.

  return val ** 3;

}



// With typeof

function getDigits(val: string | number): number {

  // If typeof val is 'number', it must be a number.

  if (typeof val === 'number') {

    return Math.ceil(Math.log10(val));

  }

  // Otherwise,`val` must be a string.

  return val.length;

}



// With instanceof

function getName(name: string | Nametag): string {

  // If `name` is an instance of the class `Nametag`, it must be a Nametag.

  if (name instanceof Nametag) {

    return name.name;

  }

  // Otherwise, `name` must be a string.

  return name;

}