typescript 如何推断对象关键字

xuo3flqw  于 2023-03-09  发布在  TypeScript
关注(0)|答案(1)|浏览(100)

我试图通过迭代数组来创建一个对象,并且只选择我需要的元素。下面的例子会让这一点变得更清楚:

const items = [{ type: 'foo' }, { type: 'bar' }, { type: 'baz' }] as const

type MyItems = {
  foo: string | null
  bar: string | null
}

const myItems: MyItems = {
  foo: null,
  bar: null,
}

items.forEach(item => {
  if (item.type in myItems) {
    item.type
      // ^? (property) type: "foo" | "bar" | "baz"
  }

  if (Object.keys(myItems).includes(item.type)) {
    item.type
      // ^? (property) type: "foo" | "bar" | "baz"
  }
})

TypeScriptPlayground
我的现实生活中的例子更复杂,我不能简单地减少items
我的问题是TypeScript不能正确地推断条件后的项目类型,我不知道如何用as修复这个问题,如果可能的话,我宁愿不使用as
有没有别的办法?

iibxawm4

iibxawm41#

可以使用类型保护函数

const pickByMyItems = 
  <T extends (typeof items)[number]>(item: T): item is Extract<T, { type: keyof typeof myItems }> => 
    Object.keys(myItems).includes(item.type)

在迭代项目之前过滤项目:

items.filter(pickByMyItems).forEach(item => {
  if (item.type in myItems) {
    item.type
      // ^? (property) type: "foo" | "bar"
  }

  if (Object.keys(myItems).includes(item.type)) {
    item.type
      // ^? (property) type: "foo" | "bar"
  }
})

运动场

也可以在if条件下使用它

items.forEach(item => {
  if (pickByMyItems(item)) {
    item.type
      // ^? (property) type: "foo" | "bar"
  }
})

相关问题