Reputation: 12916
We recently had an incident on our production system. There are plently of things we could, and should, have done to mitigate this, but never the less this happend.
Typings + example code
interface StatisticObject {
Value: number,
someData: string
}
function somePromise(): Promise<{data: {Statistics: StatisticObject[] | undefined}}> {
return Promise.resolve({data: {Statistics: undefined}})
}
We had this code in production
somePromise()
.then(({ data: { Statistics } }) => {
const [{ Value }] = Statistics || []
return Value || 0
})
Example on ts playground (Error wording a bit different on ts playground)
This caused the error Cannot read property 'Value' of undefined
, because the Statistics
object was undefined, causing the ||
statement to trigger. This array was empty, thus the const [{Value}]
destructuring failed.
I have two questions regarding this
If the Statistics ||
is removed, resulting in const [{ Value }] = []
then the results are as follows (ts playground example)
Tuple type '[]' of length '0' has no element at index '0'.(2493)
Property 'Value' does not exist on type 'undefined'.(2339)
This is the errors I would expect to see even with the Statistics ||
in front, because it is possibly undefined
.
Finally; Is there a different pattern we can use to achieve the same without risking this problem agian in the future?
Upvotes: 1
Views: 323
Reputation: 10153
At the moment TypeScript can't catch that. It will in 4.1.
Let's rewrite your code to this:
const x = Statistics || []
const y = x[0]
return y.Value || 0
The inferred type of x
is StatisticObject[]
.
What's the inferred type of y
? It's StatisticObject
but it actually should be StatisticObject | undefined
because only at runtime could we know that the array is not empty.
The "failure" is in not checking that the array actually has at least one element.
As I said, 4.1 is going to improve this by correctly inferring the type of y
to StatisticObject | undefined
and forcing you to check the length before accessing it.
Upvotes: 3