Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript complains when testing the value of array elements after a shift()

I have an array of strings, created by a split operation on a larger string. I'm doing some testing on the first two elements, like so:

var tArray = tLongString.split("_")
if (tArray[0] == "local")
{
    tArray.shift()
    if (tArray[0] == "super") {
       ...

Typescript is complaining about the second if statement, because it says that I've already checked the value of tArray[0] and determined it to be "local", so it can't be "super". But of course in between I've run a shift() command, so these aren't actually the same items.

I can solve this by casting tArray to any, but is there a more Typescript-y solution?

like image 255
Danny Kodicek Avatar asked Aug 08 '26 14:08

Danny Kodicek


1 Answers

This is a longstanding design limitation of TypeScript. See microsoft/TypeScript#9998 for a very long and in-depth discussion.

In order to allow narrowing to be convenient, the language optimistically assumes that function/method calls do not have side effects that would invalidate the control flow analysis. So the call to tArray.shift() is assumed not to invalidate the check that tArray[0] === "local". This is, of course, a bad assumption.

But there aren't too many viable alternatives. TypeScript doesn't currently have a way to mark a function as changing the state or what state is changed. So it can't tell the difference in the type system between tArray.shift() (which mutates the array) and tArray.join() (which doesn't). The language could pessimistically assume that all function calls have the potential to reset control flow narrowings, but then you couldn't write console.log("hello") without losing track of the fact that tArray[0] === "local".

So we're kind of stuck with the way it is.


That means the "TypeScript-y" solution is to refactor so that you are not modifying any state via function/method calls in an place where you need type guarding to happen. Instead of accessing tArray[0] after a tArray.shift(), you could just... not modify the array and access tArray[1] instead. The specific refactoring that works best depends strongly on your use cases and the example code in the question isn't quite a minimal reproducible example so I wouldn't presume to guess.

like image 60
jcalz Avatar answered Aug 11 '26 08:08

jcalz