Typescript如何从TicketsItem数组中提取必含history属性的元素类型
问题根因
你给arr显式标注了Tickets类型,TS会优先按照你声明的类型做类型推导,不会根据数组内实际的元素值做更精确的类型收缩,因此无论你取数组中哪个元素,得到的类型都是原始的TicketsItem,history属性依然是可选状态。
解决方法
方法1:手动构造history必选的衍生类型(通用场景,不依赖数组实际内容)
直接基于原有TicketsItem接口,把history属性转为必选即可,可以结合TS内置工具类型实现:
// 写法1:交叉类型+NonNullable,逻辑最直观 type TicketsItemMustHaveHistory = TicketsItem & { history: NonNullable<TicketsItem['history']> } // 写法2:Required+Pick/Omit组合实现,效果和写法1完全一致 type TicketsItemMustHaveHistory = Omit<TicketsItem, 'history'> & Required<Pick<TicketsItem, 'history'>>
最终得到的类型里history会变成必选属性,不存在undefined类型。
方法2:从数组字面量自动提取带history的元素类型(依赖数组实际定义)
如果不想手动定义类型,想要直接从arr数组的实际元素中推断出带history的类型,可以使用TS4.9+提供的satisfies操作符,既可以校验数组符合Tickets类型约束,又不会丢失原始字面量的精确类型:
// 去掉原来的arr的Tickets类型标注,换成satisfies做约束 const arr = [ { "id": 1, "subject": "Email certificate expired", "status": "Client response pending", "addedAt": "2020-09-23", "history": [ { "date": "20-10-10", "message": "sjflsjl", "messageBy": "client" }, ] }, { "id": 2, "subject": "Issue with Email certificate", "status": "Client response pending", "addedAt": "2020-09-23" }, ] satisfies Tickets // 提取数组中所有带history属性的元素类型 type ExtractHasHistory<T> = T extends Array<infer Item> ? Item extends { history: any } ? Item : never : never type TicketsItemMustHaveHistory = ExtractHasHistory<typeof arr>
此时TicketsItemMustHaveHistory的类型就是从数组第一个元素推断出来的、history为必选的类型。
内容的提问来源于stack exchange,提问作者Moon
相关产品推荐
相关产品推荐

