从窄类型和宽类型数组推断的类型

  • 本文关键字:类型 数组 typescript
  • 更新时间 :
  • 英文 :

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[]
}

为什么itemsItemNew[]而不是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。在这种情况下允许idprop将不合理(可能导致运行时错误)。

让我们回到你的例子:

type ItemNew = { text: string };
type ItemExist = { text: string, id: number };
function fn(
itemsNew: Array<ItemNew>,
itemsExist: Array<ItemExist>
) {
const items =  [...itemsNew, ...itemsExist];
}

实际上itemsArray<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
}

相关内容

  • 没有找到相关文章