我有一个带有可选ID的书的界面(例如,一本尚未保存到服务器的新书):
interface Book {
id?: string
}
当我从后端获取所有书籍时-我使用byId创建对象:
allIds: payload.map(book => book.id!),
其中allIds
声明为:
allIds: string[]
如您所见,我在!
之后添加了book.id
,以指定每本书都有一个ID。
好像我不会那样做,Typescript不会使用:
TS2322:类型'(string | undefined)[]'不能分配给类型'string []'。
键入“字符串| undefined”不能分配给“ string”类型。
类型'undefined'不能分配给类型'string'。
现在,它正在与!
配合使用,我不希望任何一本书都会丢失其ID,但是我想找到一种验证它的优雅方法。
我可以做类似的事情:
allIds: payload.map(book => {
if (!book.id) {
throw new Error("invalid book id")
}
return book.id
}),
但是我想知道您是否有更好的单线优雅解决方案来在映射项目时验证项目的想法。
答案 0 :(得分:2)
我不希望任何一本书都缺少它的ID
然后从界面中删除onclick
。
如果您想过滤掉没有?
的元素,那么id
将是所有字符串,并且如果您坚持使用单线:
allIds
如果由于某种原因您无权访问const allStrings: string[] = payload.map(book => book.id).filter(<T>(v: T): v is Exclude<T, undefined> => typeof v !== 'undefined');
界面,则可以将这种类型用于输入数据:
Book
这将使Required<Book>
不再是可选的。
答案 1 :(得分:1)
如何将断言逻辑封装在单独的函数中?
function assertDefined<T>(t: T | undefined | null): T {
if (t == undefined) throw new Error("undefined or null item.")
return t
}
const res = payload.map(book => assertDefined(book.id)) // string[]
您可以定义一个propOrThrow
函数以使其更短:
function propOrThrow<T, U>(mapper: (t: T) => U | undefined) {
return (t: T): U => assertDefined(mapper(t))
}
const res2 = payload.map(propOrThrow(b => b.id)) // string[]