【发布时间】:2022-08-18 15:08:20
【问题描述】:
有许多示例说明如何为非空数组设计类型保护。例如this method 在使用noUncheckedIndexedAccess 时效果很好:
type Indices<L extends number, T extends number[] = []> = T[\"length\"] extends L
? T[number]
: Indices<L, [T[\"length\"], ...T]>;
export type LengthAtLeast<T extends readonly any[], L extends number> = Pick<
Required<T>,
Indices<L>
>;
// Borrowed from: https://stackoverflow.com/a/69370003/521097
export function hasLengthAtLeast<T extends readonly any[], L extends number>(
arr: T,
len: L
): arr is T & LengthAtLeast<T, L> {
return arr.length >= len;
}
export function isNotEmpty<T extends readonly any[]>(arr: T): arr is T & LengthAtLeast<T, 1> {
return hasLengthAtLeast(arr, 1);
}
然后:
let foo = [1, 2, 3];
if (isNotEmpty(foo))
foo[0].toString() // does not error
else
foo[0].toString() // does error
然而,要检查这个的逆必须反转布尔检查:
let foo = [1, 2, 3];
if (!isNotEmpty(foo))
foo[0].toString(); // now errors
else
foo[0].toString(); // now does not error
问题是我认为if (!isNotEmpty(foo)) 读起来有点难看,因为它是双重否定的。
那么问题来了,如何定义一个isEmpty 类型守卫,这样就可以做到if (isEmpty(foo)) 并且仍然得到与上面显示的代码sn-p 相同的结果?这似乎是一个微不足道的问题,但到目前为止我的所有尝试都遭到了挫败。
我认为主要问题是你不能断言类型保护的逆,你不能说某事不是别的东西。
编辑:我被要求提供更多示例。
所以这是我想做的一个例子:
function logFirstDataElement(data: number[]) {
// Dont do anything if no data
if (isEmpty(data)) return;
// this should not error because data should have been narrowed to
// [T, ...T]
// that is, it should have at least one element
console.log(data[0].toString())
}
可以通过执行以下操作来实现
function logFirstDataElement(data: number[]) {
// Dont do anything if no data
if (!isNotEmpty(data)) return;
console.log(data[0].toString())
}
但如上所述,我宁愿避免!isNotEmpty(data) 的“双重否定”
-
回复:您的update:向编译器断言数组不为空并不会断言它在索引
0处具有值。这些是不同的断言,需要不同的类型保护。 (例如,数组不能为空,但前 200 个元素是undefined,第一个未定义的元素仅出现在索引 200 处。) -
也许值得使用
const isFilled=(arr:any[]): arr is [any, ...any[]]=> your code。只需使用两个 typeguard
标签: typescript types