type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
function fn(
itemsNew: Array<ItemNew>,
itemsExist: Array<ItemExist>
) {
const items = [...itemsNew, ...itemsExist];
// const items: ItemNew[]
}
为什么items
是ItemNew[]
而不是Array<ItemNew | ItemExist>
?似乎关于宽类型(ItemExist
)的信息只是丢失了。
考虑这个例子:
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
因为text
是共同的两个项目,你可以得到text
属性。
因为没有人知道var union
是否包含id
。在这种情况下允许id
prop将不合理(可能导致运行时错误)。
让我们回到你的例子:
type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
function fn(
itemsNew: Array<ItemNew>,
itemsExist: Array<ItemExist>
) {
const items = [...itemsNew, ...itemsExist];
}
实际上items
是Array<ItemNew> | Array<ItemExist>
的并集。同样的规则也适用。属性text
是唯一安全的属性。
如果你想获得id
属性,你可能需要使用这个帮助器:
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
}