TypeScript says that variable is possibly `null` after `Array.prototype.includes(null)`

79 views Asked by At

I have a multiple variable null check:

const path = window.location.pathname
const regex_list = path.match(/\d+/g) // 100% have at least 1 number
const a = document.querySelector('')
const b = document.querySelector('')

if (![regex_list, a, b].includes(null)) {
  regex_list[0]
}

TS gives error:

'regex_list' is possibly 'null'. (tsserver 18047)

enter image description here

Even here:

if (![regex_list].includes(null)) {
  regex_list[0]
}

Info about regex_list:

const regex_list: RegExpExecArray | null

enter image description here

If it is not null than it must be RegExpExecArray, but TS doesn't think so. Is it because it only supports ==/!=/===/!== operators? If yes, then can I safely ignore this error with // @ts-ignore or regex_list![0]?


Update:

Since there are already answers to the main question, I also found an answer to the sub-question about ignoring the error. Instead, an assertion can be used to narrow the type: (regex_list as RegExpExecArray), but it has to be done for every reference of the regex_list (answer).

2

There are 2 answers

3
Matthieu Riegler On

Array.include() is defined as following :

includes(searchElement: T, fromIndex?: number): boolean;

As you can see, there is no predicate, so typescript won't narrow down and remove the null from the type.

1
Lipez_47 On

You can be sure that the array is not null with ![regex_list, a, b].includes(null), but You're not sure if the array is empty, because it can exist like this []. Also, since you need to have the first element of the array, you need to see that the array is not empty.

For that you can check the size of the array with regex list.length > 0 in the conditional or use regex list! [n] (will return undefined if it does not exist).

So, to fix it you can simply add this condition:

const path = window.location.pathname
const regex_list = /\d+$/.exec(path)
const a = document.querySelector('')
const b = document.querySelector('')

if (a && b && regex_list && regex_list.length > 0) {
    regex_list[0]
}

You can also take this into account:

console.log([]) // -> true