打字脚本 - 验证数组映射中的项目



>我有一个带有可选ID的书的界面(例如,一本尚未保存到服务器的新书(:

interface Book {
id?: string
}

当我从后端获取所有书籍时 - 我用来创建一个对象 byId:

allIds: payload.map(book => book.id!),

其中allIds声明是:

allIds: string[]

如您所见,我在book.id后添加了!,以指定每本书都有一个 Id。 好像我不会那样做,打字稿不会编译:

TS2322:类型"(字符串|未定义([]"不能分配给类型"字符串[]"。

类型"字符串|未定义"不能分配给类型"字符串"。

类型">

未定义"不可分配给类型"字符串"。

现在,它正在与!一起工作,我不希望任何一本书缺少它的id,但我想找到一种优雅的方式来验证它......以防万一。

我可以做这样的事情:

allIds: payload.map(book => {
if (!book.id) {
throw new Error("invalid book id")
}
return book.id
}),

但我想知道您是否对更好的单行优雅解决方案有任何想法,以便在映射时验证项目。

我不希望任何一本书缺少它的id

然后从界面中删除?

如果你想过滤掉没有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>

这将使id不再是可选的。

如何将断言逻辑封装在一个单独的函数中?

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[]

代码示例

最新更新