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
CodePudding user response:
Indexed access on a type will not return undefined.
type array = Array<string>;
type firstItemType = array[0] // string;
CodePudding user response:
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
}