Home > Enterprise >  Why assigning an array item to variable can avoid TS possibly null error, but directly accessing it
Why assigning an array item to variable can avoid TS possibly null error, but directly accessing it

Time:10-05

I would like to know the difference between assigning an array item to variable and accessing directly to it. As I show in the code below, #1 hits the possibly null error, but #2 and #3 doesn't. Those results are same, right? Anyone knows how this is working?

interface NumInterface {
  key1: number | null;
}

const numList: NumInterface[] = [{ key1: 1 }];

const fooFunc = (index: number) => {
  // pass unchecked indexed accesses
  if (!numList[index]) return;

  // #1
  // can not avoid "possibly null"
  if (!numList[index].key1) return;
  numList[index].key1   1; // this outputs "Object is possibly 'null'."

  // #2
  // can avoid "possibly null"
  const target = numList[index].key1;
  if (!target) return;
  target   1;

  // #3
  // can avoid "possibly null"
  if (!numList[0].key1) return;
  numList[0].key1   1;
};

CodePudding user response:

The underlying issue here is a longstanding missing feature of TypeScript requested microsoft/TypeScript#10530.

TypeScript's control flow analysis, which lets the compiler see that x must be truthy after if (!x) return;, only works on property accesses when the property name is a known literal like 0 or "foo". If the property name is a wide type like number or string, or if it is a union type like 0 | 1 or "foo" | "bar", or if it is a generic type like I extends number or K extends string, the control flow analysis doesn't happen.

That's because currently the compiler just looks at the type of the indexer and not its identity. It can't see the difference between if (!obj[k]) return; obj[k].toFixed() and if (!obj[k1]) return; obj[k2].toFixed() if k, k1, and k2 are all of the same type. If that type happens to be a single literal type like 0 or "foo", then control flow analysis is fine, because then k1 and k2 would definitely hold the same value even though they are different variables. But if it's a wide type or a union type or a generic type, then control flow analysis is not safe because it could hold different values.

Again, this is a missing feature, not a problem with your code. Obviously there is a difference between if (!obj[k]) return; obj[k].toFixed() and if (!obj[k1]) return; obj[k2].toFixed(). The fact that the indexer k is identical in both checks and is not reassigned between them guarantees that you are checking a property and then acting on the same property. But currently the compiler doesn't notice or act on this identity. The first time an attempt to fix microsoft/TypeScript#10530 caused an unacceptable degradation in compiler performance. It's possible that at some point it will be revisited with more performant code. If you want to go to that issue and give it a

  • Related