Typescript: passing array type check result to a variable

I have a piece of code where I need to know in a few different places whether or not a variable is an array (it can be an array or string). If it is, I map over the data. If not, I do something else.

Simplified code, which typescript complains about:

function myFunc(input: unknown[] | string) {

  const isArray = Array.isArray(input);
  
  if (isArray) {
    // this line throws an error, since `map` is not a valid method for strings
    return input.map(/* do stuff here*/);
  }

  return input;

}

If I change the line with the if statement to this:

  if (Array.isArray(input))

then typescript seems to understand that input is in fact an array.

I use that check in several places in the real code though, and would like to use a single variable for readability, rather than doing Array.isArray every time.

What’s going on here?

Answer

Typescript 4.4+

What you want do does work in Typescript 4.4 (unreleased as of July 6, 2021)

See blog post detailing aliased conditions

Playground using nightly build


Typescript 4.3

In earlier versions of typescript your options are a bit more limited. The problem is that typescript is not smart enough to understand that const isArray is derived from Array.isArray(input). After that line, it’s just a boolean value with no connection to any other value.

I would probably create an intermediate variable that only has a value if the input is an array. That way typescript can keep track of that type on one single variable.

Something like:

function myFunc(input: unknown[] | string) {
  const inputArray = Array.isArray(input) ? input : null

  if (inputArray) {
    return inputArray.map(str => str);
  }

  return input;
}

Playground