Consider this example:
type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
type Union = ItemNew | ItemExist
declare var union: Union
const elem = union.text // only text property is allowed
Because text
is common for both items you are allowed to get text
property.
Because nobody knows whether var union
contains id
or not. Allowing id
prop in this case will be unsound (might cause runtime error).
Let's go back to your example:
type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
function fn(
itemsNew: Array<ItemNew>,
itemsExist: Array<ItemExist>
) {
const items = [...itemsNew, ...itemsExist];
}
In fact items
is a union of Array<ItemNew> | Array<ItemExist>
. Same rule is applied. Property text
is the only one safe property.
If you want to be able to get id
proeprty you might wonna use this helper:
type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
// credit goes to https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
T extends any
? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
function fn(
itemsNew: Array<ItemNew>,
itemsExist: Array<ItemExist>
) {
const items: Array<StrictUnion<ItemNew | ItemExist>> = [...itemsNew, ...itemsExist];
items[0].text // ok
items[0].id // number | undefined
}