Typescript不理解对象数组中未定义值的过滤器



我努力让typescript理解,我已经处理了一个属性(project)在这个(缩短)示例中的未定义情况:

interface Entry {
id: number
project?: Project
isPublished?: boolean
}
entries
.filter(entry => !!entry.project)
.map(entry => ({
title: entry.project.title
}))

(entries是这里的Entrys数组)和编译器在project属性上的entry.project.title行上抱怨TS2532: Object is possibly 'undefined',即使我有过滤器删除未定义的。另一个可选属性在过滤之后仍然是可选的,因此我不能使用Required接口:/

我怎样才能使TS理解属性在映射函数中明确定义?

谢谢

—编辑:添加了另一个可选的属性/澄清,作为对所有属性都需要的建议答案的回应

您需要将filter回调定义为类型保护,并使用Required类型util使所有接口道具必需:

type Project = {
title: string
}
interface Entry {
id: number
project?: Project
}
type WithProject = Required<Entry>
declare const entries: Entry[]

entries
.filter((entry): entry is WithProject => !!entry.project)
.map(entry => ({
title: entry.project.title
}))

游乐场

如果您对更多类型utils感兴趣,请参阅docs

添加@captain-yossarian的答案并解决OP对此的评论,我们可以创建自己的实用程序类型,只需要几个特定的键:

type Project = {
title: string
}
interface Entry {
id: number
project?: Project
}
type SomeAreRequired<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
type WithProject = SomeAreRequired<Entry, "project">;
declare const entries: Entry[]
entries
.filter((entry): entry is WithProject => !!entry.project)
.map(entry => ({
title: entry.project.title
}))

SomeAreRequired选择T中的所有键都是必需的,然后将其添加到T中,而省略K键,从而有效地使选中的键成为必需的。

游乐场

最新更新