Reputation: 85
I faced some difficulties with typescript destructuring array typification. Can't make array destructuring with typescript.
I got some data from a server. This data has the type (ISpecType[] | undefined)
interface ISpecType {
id: string
doughTypes: object[]
sizes: object[]
chosenDoughType: string
chosenSize: number
pizzaId: string
}
// omitted the fetch logic of getting data
// 'data' equals =
data = [
{
chosenDoughType: "Thin"
chosenSize: 26
doughTypes: (2) [{…}, {…}]
id: "7p5Xca6DykcUkvE8A7P4p"
pizzaId: "VYyLBL3l5JXhUAqXOb-rt"
sizes: (3) [{…}, {…}, {…}]
}
]
// the code where the error comes up.
const [single]: ISpecType[] | undefined = data
After that, I got this message:
ERROR in src/features/pizzas/PizzaSpecsButtons.tsx:30:11
TS2461: Type 'ISpecType[] | undefined' is not an array type.
28 | }),
29 | })
> 30 | const [single]: ISpecType[] | undefined = data
| ^^^^^^^^
The type of data mustn't be changed!
How to tackle it?
Upvotes: 1
Views: 820
Reputation: 330456
There are two possible failure cases you need to consider when you write const [single] = data
, if all you know about data
at compile time is that it is of type ISpecType[] | undefined
.
First: data
can be undefined
. If so, then the line const [single] = data
will attempt to destructure undefined
, which will result in a runtime TypeError. That's why the compiler is giving you an error.
In order to prevent this from happening, you can use the nullish coalescing operator (??
) to replace undefined
with an empty array, so that single
will be undefined
:
const [single] = data ?? [];
But wait, when you check the type of single
, the compiler thinks it is definitely ISpecType
and not ISpecType | undefined
:
// const single: ISpecType
Oops. That brings us to the second failure case.
Second: data
can be an empty array. If so, then const [single] = data
will end up making single
undefined, but the compiler unfortunately does not catch this. TypeScript give arrays a numeric index signature, and traditionally assumes that if you index into an Array<X>
with a numeric index, you'll get a value of type X
. Yes, it's possible for it to be undefined
, but the compiler doesn't consider the possibility. If you forget to check for undefined
, you're likely to hit a runtime error even though the compiler thinks it's fine. This has been a longstanding issue; see microsoft/TypeScript#13778.
And you can actually enable the --noUncheckedIndexedAccess
compiler option to enable stricter checking, at which point things would work:
// with --noUncheckedIndexedAccess enabled
const [single] = data ?? [];
// const single: ISpecType | undefined
But this compiler option is not part of the standard --strict
suite of compiler options because it tends to be annoying to use, and it affects your whole code base. Instead of this I recommend providing an explicit undefined
entry in your default array, so that the compiler is aware of the possibility:
// regardless of --noUncheckedIndexedAccess
const [single] = data ?? [undefined]
// const single: ISpecType | undefined
Now you have a single
of type ISpecType | undefined
and the compiler is happy.
Upvotes: 2