Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript with strict null checking - what about array access?

In TypeScript, if strict null checking is enabled, I would expect the compiler to prevent me from assigning null or undefined values to a variable unless it admits null.

However, array access seems to allow circumventing this check.

Example:

let a: string[] = ["Hello"];
let s: string;

// 1) this produces an error, as expected
s = undefined

// 2) s is undefined here, too, but no error
s = a[3];
console.log(s);

Runnable version on the TypeScript Playground (Note: "strict null checking" must be enabled in the "Options" dialog).

What is going on here?

  • Is this a bug in the TypeScript compiler?
  • Or is it a deliberate omission?
  • If the latter, is this documented anywhere (ideally with a rationale why it was done) ?
like image 305
sleske Avatar asked Dec 08 '17 17:12

sleske


2 Answers

Found it :-).

tl;dr: It is a deliberate omission. Array access is very common in TypeScript code, and forcing a null/undefined check for every access was considered too cumbersome for developers.

Note that since TypeScript 4.1 this is configurable with the compiler option noUncheckedIndexedAccess. See Klaster_1's answer for details.


The issue has been raised several times in discussions:

  • issue #11122 - Array lookup should return T | undefined
  • comment on PR 7140
  • #6229 - Proposal: strict and open-length tuple types

The comment on PR 7140 has a nice rationale from Anders Hejlsberg (one of the core developers):

Indexing simply produces a value of the type declared in the matching index signature. Even if it is technically more correct, it would simply be too painful if we automatically added undefined to the type of every indexing operation.

For example, every array element access would have to be accompanied by a non-null guard or a ! assertion. I think that would become hugely irritating.


Personal comment: I think this is a reasonable decision. The problem is inherent with arrays - I don't think it's possible to prove (for the compiler) whether a given position is defined, since you can use calculated positions. So any warning would produce many false positives, and most devs would switch it off anyway.

Essentially, arrays provide more freedom to the developer than the compiler can check. If you want proper checking, the only solution I can see is to avoid direct array access, and use other data structures that provide more protection.

like image 158
sleske Avatar answered Sep 28 '22 01:09

sleske


TypeScript 4.1 introduced a new compiler option - noUncheckedIndexedAccess. Among other things, it adds undefined to array index access type.

Consider the following snippet (TS playground):

const items = [1,2,3]
console.log(items[1]?.toString(10))
console.log(items[2].toString(10))

Without noUncheckedIndexedAccess, items[2].toString(10) will be deemed valid, and invalid when the option is on. The items[1]?.toString(10) will be valid when the option is on, just like in comment by Alex Neth in the older answer.

like image 31
Klaster_1 Avatar answered Sep 28 '22 00:09

Klaster_1