【问题标题】:Inferred type from arrays of narrow and wide types从窄类型和宽类型的数组推断类型
【发布时间】:2021-11-05 02:18:37
【问题描述】:
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&lt;ItemNew | ItemExist&gt;?似乎有关宽类型 (ItemExist) 的信息完全丢失了。

【问题讨论】:

  • 因为Best common type推断
  • @RickyMo 我不知道这种行为已被明确记录。感谢您的链接!
  • ItemNew | ItemExist 在逻辑上与ItemNew 相同。如果某物是水果或苹果,那么您不妨直接说它是水果。

标签: typescript


【解决方案1】:

考虑这个例子:

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 属性是不合理的(可能会导致运行时错误)。

让我们回到你的例子:

type ItemNew = { text: string };
type ItemExist = { text: string, id: number };

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

实际上itemsArray&lt;ItemNew&gt; | Array&lt;ItemExist&gt; 的联合。应用相同的规则。财产text 是唯一安全的财产。

如果你想获得id proeprty,你可能不会使用这个助手:

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
}

【讨论】:

  • 你的例子和我的不一样。在您的情况下,仍然可以在类型保护的帮助下引用 id,例如:if ('id' in union) { const elem = union.id }。在我的情况下,关于 id 的信息完全丢失了。
  • 我的问题似乎更容易解决:const items: Array&lt;ItemNew | ItemExist&gt; = [...itemsNew, ...itemsExist],因为我最终不需要混合类型。但是感谢 StrictUnion 的解决方案!
  • @Dartess 是的,这在我看来像是过度工程:D
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
  • 2014-08-27
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多