arrays - 循环嵌套数组时如何正确使用类型保护?
问题描述
在遍历数组时,我需要区分其元素的两种可能类型:
- 每个元素都是一个字符串,或者
- 每个元素都是一个字符串数组。
function _addDataAtIndex(
totalData: Array<string | string[]>,
dataToAdd: Array<Array<string | string[]>>,
addIndex: number,
) {
dataToAdd.forEach((dataArr) => {
if (dataArr.every((x) => typeof x === 'string')) {
// each value is a string - insert the entire array
totalData.splice(addIndex, 0, dataArr);
} else {
totalData.splice(addIndex, 0, dataArr[0]);
}
});
}
然而,TypeScript 似乎无法推断嵌套数组的类型,即使看起来很健壮的类型保护也是如此。我仍然需要类型保护来确保我在正确的分支上,但是我必须转换数组,dataArr as string[]
来告诉 TypeScript 没有问题。这是多余且脆弱的,我觉得必须有一种方法可以使用更清洁的防护装置来做到这一点。
我已经搜索了许多其他问题,但是我在那里找到的答案(例如自定义类型保护函数)也不起作用,请参阅这个游乐场。
string | string[]
有没有一种干净的方法可以在不改变整个结构的情况下进行区分?我所能想到的就是将内部值转换为一些自定义联合接口的对象,这对于这个用例来说太混乱了。
解决方案
TypeScript 无法理解您.every
作为类型保护的调用。您可以为此编写自己的类型保护/谓词,尽管这不是必需的。类型 for.every
有两个重载,一个是实际谓词:
/**
* Determines whether all the members of an array satisfy the specified test.
* @param predicate A function that accepts up to three arguments. The every method calls
* the predicate function for each element in the array until the predicate returns a value
* which is coercible to the Boolean value false, or until the end of the array.
* @param thisArg An object to which the this keyword can refer in the predicate function.
* If thisArg is omitted, undefined is used as the this value.
*/
every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[];
/**
* Determines whether all the members of an array satisfy the specified test.
* @param predicate A function that accepts up to three arguments. The every method calls
* the predicate function for each element in the array until the predicate returns a value
* which is coercible to the Boolean value false, or until the end of the array.
* @param thisArg An object to which the this keyword can refer in the predicate function.
* If thisArg is omitted, undefined is used as the this value.
*/
every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean;
要使用类型保护重载版本,您传递给的谓词.every
本身必须是类型保护。您可以简单地向数组函数添加一个返回类型,将其标记为类型保护:
function _addDataAtIndex(
totalData: Array<string | string[]>,
dataToAdd: Array<Array<string | string[]>>,
addIndex: number,
) {
dataToAdd.forEach((dataArr) => {
// Note the `: x is string` here
if (dataArr.every((x): x is string => typeof x === 'string')) {
// each value is a string - insert the entire array
totalData.splice(addIndex, 0, dataArr);
} else {
totalData.splice(addIndex, 0, dataArr[0]);
}
});
}
现在它使用类型保护版本,.every
它使 TypeScript 意识到dataArr
它是string[]
if 语句的那个分支中的一个。
推荐阅读
- macos - install4j 如何为 macOS 单包存档创建自定义安装程序
- reactjs - 避免在每次渲染 react-modal 时重新创建 body 组件
- python - 如何从年龄字段中估算出大致的出生日期?
- go - 使用 envoy 代理验证器和 gogo protobuf 进行验证
- python - Python - to_dict('records') 创建列表类型需要字典来访问值
- go - 具有 go 反射的复杂对象的 Unmarshal 方法
- javascript - 使用 XLSX/SheetJS 向 Excel 列添加约束
- python - 分析后如何确认消息
- c++ - How to calculate maximum/minimum over n-channels in Halide using domains?
- gstreamer - jpeg 图像的 GStreamer 管道