Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Nullish Coalescing in Typescript

With the release of Typescript 3.7 there is now support for Nullish Coalescing. However it seems like I am using it wrongly.. I have the following structure:

type myType = { ["myKeys"]?: Array<string> }
let data: myType;
data = {};
data["myKeys"] = ["index0"];

console.log(data?.["myKeys"]?.indexOf("index0")) // 0 

if (data?.["myKeys"]?.indexOf("index0") ?? -1 === -1) { // returns false
} else {
    console.log("returns false");
}

data["myKeys"].push("index1")
console.log(data?.["myKeys"]?.indexOf("index1")) // 1

if (data?.["myKeys"]?.indexOf("index1") ?? -1 === -1) { // returns true - why?
    console.log("Why is it true"); 
}

Why does the ?? operator behave differently when the index of index1 is 1 while the index of index0 is 0. Both should return false since it's !== -1

Playground link

like image 754
Murat Karagöz Avatar asked Jan 26 '23 14:01

Murat Karagöz


2 Answers

It's a precedence issue. Your code is being evaluated as:

if (data?.["myKeys"]?.indexOf("index1") ?? (-1 === -1)) {
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^−−−−−−−−−^
    console.log("Why is it true");
}

but your intention is:

if ((data?.["myKeys"]?.indexOf("index1") ?? -1) === -1) {
// −^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^
    console.log("Why is it true");
}

Oddly, I don't see precedence discussed in the proposal though it is mentioned in the draft spec as Jonas mentions, and it does come up in the issues.

As you can see, this is consistent with the precedence of ||, which is its very, very near relative:

const a = 2;
const b = -1;
console.log(`${a} || ${b} === ${b}:   ${a || b === b}`);
console.log(`(${a} || ${b}) === ${b}: ${(a || b) === b}`);
console.log(`${a} || (${b} === ${b}): ${a || (b === b)}`);

According to the draft spec, ?? has lower precedence than || (presumably just lower). (To avoid confusion, it's also not allowed in an && or || expression.)

like image 58
T.J. Crowder Avatar answered Jan 28 '23 05:01

T.J. Crowder


To quote from the draft:

?? has lower precedence than ||

Or in other words, your code behaves roughly like:

  data?.["myKeys"]?.indexOf("index0") || -1 === -1

And that'll be treated as:

 (data?.["myKeys"]?.indexOf("index0")) || (-1 === -1)
like image 28
Jonas Wilms Avatar answered Jan 28 '23 03:01

Jonas Wilms