2

strictNullChecks is a great option, which can help developers avoid many potential runtime errors. So I recently started to refactor my code with this option enabled. But then I came across a small but slightly annoying scenario:

if (array?.length > 0) {
    // do something with `array`
}

I have a habit of using such syntax to obtain a non-empty array, taking advantage of the JavaScript feature that comparing anything with undefined using < or > results in false. However, this syntax is disallowed under strictNullChecks, which means I have to write it in a verbose way:

if (array != null && array.length > 0) {
    // do something with `array`
}

Well, maybe not that verbose, but when array is a long chaining expression instead of a simple variable, the previous syntax really saves your life (or otherwise you'll have to choose between repeating this long expression or assigning it to a variable beforehand).

Is there another option to allow this specific scenario? Since I don't want to lose the benefit of strictNullChecks either.

Or some inspirations on why TypeScript decided to ban comparing undefined with other values using < or > are also welcomed. I understand that many view this feature more of a pitfall which should be circumvented by every means, since it's not very semantic, especially for starters. But I do appreciate the convenience of using it in such a scenario. So is clarity the only consideration for banning it? Or there are still some potential runtime impacts that I've left out?


Well, as pointed out in the comments, the scenario above could be simply solved by removing > 0, since both undefined and 0 are considered falsy.
While there are other scenarios where we want to compare a possibly undefined or null value with a non-zero number, array?.length ?? 0 will do the trick (but TypeScript won't deduce that array is neither undefined nor null in the following block, we still need the non-null assertion operator).
So, the major problem is basically solved. But I'm still curious about the motivation that drives TypeScript developers to prohibit comparison between possibly null or undefined numbers with strictNullChecks on. Therefore, I decided to keep this question open for discussion.

0x269
  • 688
  • 8
  • 20
  • Does `if (array?.length) {` work for you? It relies on the fact that undefined and 0 are falsy, and all non-zero numbers are truthy. If not, what am I missing? – Lesiak Nov 14 '22 at 13:24
  • I haven't used much typescript lately, but in other languages I usually use the null-coalescing operator for that: `(array ?? []).length > 0` or `(array?.length ?? 0) > 0`. Would that be an acceptable alternative? – nd. Nov 14 '22 at 13:37
  • @nd. These are not the same. In the original code the if condition is entered ONLY if array is not empty. Post author does not specify what happens in the if block and if the non-empty check is necessary (a lot of times code processing arrays element-wise can accept empty arrays, and the only check necessary is if array is truthy) – Lesiak Nov 14 '22 at 13:48
  • @Lesiak How stupid I am! Yeah, of course, this definitely works as intended. I'll edit the question to move to the latter topic. – 0x269 Nov 14 '22 at 15:01

1 Answers1

2

As you noticed array?.length > 0 is not allowed with strictNullChecks: If array is undefined, it reduces to undefined > 0.

The if condition can be simplified in a way which works fine with strictNullChecks.

if (array?.length) {
   // process non-empty array
}

The code above relies on the fact that undefined and 0 are falsy, and all non-zero numbers are truthy.

If the code inside the if block can accept empty arrays, the condition can be further simplified to:

if (array) {
   // process empty array or non-empty array
}

While I'm not in a position to discuss design decisions, strictNullChecks on says:

With strictNullChecks on, when a value is null or undefined, you will need to test for those values before using methods or properties on that value.

If property or method access is disallowed on possibly undefined object, it is consistent to disallow <,<= operators as well. Not only being consistent, it removes surprising behaviour of JS: Why isn't undefined less than 1?

// JS
undefined <= undefined  // false
undefined > undefined   // false  
Lesiak
  • 22,088
  • 2
  • 41
  • 65