我努力让typescript理解,我已经处理了一个属性(project
)在这个(缩短)示例中的未定义情况:
interface Entry {
id: number
project?: Project
isPublished?: boolean
}
entries
.filter(entry => !!entry.project)
.map(entry => ({
title: entry.project.title
}))
(entries
是这里的Entry
s数组)和编译器在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
键,从而有效地使选中的键成为必需的。
游乐场