Typescript error "Object is possibly 'undefined'." occurs when I use
array.at(-1).key //array[array.length - 1].key
For example, error does not occur with the code below
class P {
public x: number
public constructor(x: number) {
this.x = x
}
}
const a = [new P(1)]
console.log(a[a.length - 1].x)
However, error does occur with the code below
class P {
public x: number
public constructor(x: number) {
this.x = x
}
}
const a = [new P(1)]
console.log(a.at(-1).x)
It also occurs when I checked if the value is undefined.
class P {
public x: number
public constructor(x: number) {
this.x = x
}
}
const a = [new P(1)]
if (a.at(-1) !== undefined) console.log(a.at(-1).x)
The square brackets operator for array indexing has existed since the birth of JavaScript. For the longest time, it was the only way to index into an array. Yes, it returns undefined
for array indexes or object keys that don't exist. But because of how pervasively this operator is used in essentially all code, and how verbose and annoying it would be to check if the indexing result is undefined
, it seems TypeScript decided to break strict soundness and pretend that the result isn't undefined
.
Array.at()
is a bleeding-edge new method introduced in ES2022. Indeed, I see that the current TypeScript compiler treats the method's semantics strictly and forces you to check if the result is undefined
.
As for why the code if (a.at(-1) !== undefined) console.log(a.at(-1).x)
doesn't work, it's because common subexpression elimination cannot be assumed to be valid in general. The method could be monkey-patched and/or have side effects (including modifying the array itself). The way to make that piece of code type-check properly is with a temporary variable, which guarantees that it won't be modified between the time of check and the time of use, like this:
const temp = a.at(-1);
if (temp !== undefined)
console.log(temp.x);