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
undefined.const [single]: (ISpectType | undefined)[] | undefined = data??[], does that work for you? If so, I could write up an answer explaining. If not, why not?data ?? []. Getting a default empty array in case of an undefined response.