1

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?

17
  • 1
    Well, you cannot destructure undefined. Commented Jun 13, 2022 at 15:07
  • 1
    I would write const [single]: (ISpectType | undefined)[] | undefined = data??[], does that work for you? If so, I could write up an answer explaining. If not, why not? Commented Jun 13, 2022 at 15:17
  • A response from a server might be undefined, but a full data response is actually got well. Commented Jun 13, 2022 at 15:17
  • 1
    @jcalz, When I wrote, "And it is worth nothing to insert a default empty array in a case of an undefined response." I actually meant "And this is not hard to write something like this": data ?? []. Getting a default empty array in case of an undefined response. Commented Jun 13, 2022 at 16:27
  • 1
    @jcalz, Yes, I want you to write an answer. Commented Jun 13, 2022 at 16:28

1 Answer 1

2

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.

Playground link to code

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your clear answer. That one helped me a lot. I appreciate it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.