2

Can anyone explain this?

Why is undefined not an option if type is a union of empty array and array of data when accessing an item

type emptyArray = []
type accessEmptyArray = emptyArray[0] // returns undefined

type validData = {id:number, name:string}
type someData = validData[] | []

type test = someData[0] // returns type validData but could also be undefined

I assume I can solve this by using an assertion but it will make my code quite verbose.

I'm quite surprised by this issue as it seems like a problem that is easily overlooked and the type of problem that TS is built to solve but maybe I haven't thought of a downside to my assumed way of it working

Example: Playground

2 Answers 2

2

That's as design.

Indexed access on a type will not return undefined.

type array = Array<string>;
type firstItemType = array[0] // string;
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @matthieu-riegler, noUncheckedIndexedAccess is exactly what I need. My code has lit up with red all over it - but it's a price I'm willing to pay!
0

In order to understand that, please be aware that :

type EmptyArray = []
type EmptyArray2 = never[]

both EmptyArray and EmptyArray2 are equal. Empty array, in TypeScript is infered as never[].

Try this:

type EmptyArray = []
type Item = EmptyArray[number] // never

Hence, union of both empty and non empty looks like this:

type ValidData = { id: number, name: string }

type Union = Array<ValidData> | never[]

type NonEmptyElement = Array<ValidData>[number] // ValidData
type EmptyElement = never[][number]             // never

type Result = Union[0] // ValidData | never -> ValidData

When you make union of empty / non empty array and trying to obtain first element, you basically obtaining union of ValidData | never, which is equal to just ValidDate.

If you are curious why never is meaningless in any union, see this answer


As for the error in:

type emptyArray = []

type accessEmptyArray = emptyArray[0] // returns undefined

This is because emptyArray does not have any elements, and type script does not allow even to use 0, however, you are still allowed to use index of Array:

type accessEmptyArray = emptyArray[number] // never

This is because Array has this type signature:

interface Array<T> {
  [n: number]: T
}

4 Comments

The union is not the cause here : ` type array = Array<string>; type firstItemType = array[0] // string; `
@MatthieuRiegler but OP has provided an empty array as literal array: [] which is equal to Array<never> and it can't be comparable to Array<string>. This is different case
Thanks a lot @captain-yossarian-from-ukraine there's definitely some interesting things explained in there but I really need undefined, not never. Using noUncheckedIndexedAccess compilerOption in the tsconfig will work for me. Thanks again!
@MatthieuRiegler you are right, it seems that I completely missed the point. Upvote from me

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.