TypeScript 能否判断一个数组是否非空,并相应地推断某些数组方法的类型?
我最近更新了 TypeScript 和 Lodash,现在编译器能够理解,例如方法 _.last() 如果数组非空会返回一个值,如果数组为空则返回 undefined。这是预期的行为,尤其是当我们不知道数组是否为空时。
然而,在诸如调用 _.last([1,2,3]) 的情况下,我们只是知道数组非空,并且这总会返回一个数字。此外,我在代码中有几个地方检查了非空情况,并相应地采取了行动,比如:
if (!_.isEmpty(array)) {
return _.last(array);
}
... 仅仅通过查看那段代码,我们就知道该语句将返回该数组中某个元素类型的元素。但返回类型仍然是 T | undefined。
我知道在这种情况下我可以直接转换值。但我宁愿避免转换东西。
所以我的问题是:TypeScript 有可能理解像这样的情况吗?
答案#1
我们可以创建一个系统,其中 isEmpty 会向数组的类型添加信息。这可以是一个我们称之为 HasElements<T> 的类型,其中 T 可以是 true 或 false。如果类型尚未经过测试,它的类型中应该包含两种可能性(T[] & (HasElements<true> | HasElements<false>))。不幸的是,这必须手动添加到类型中。
import _ from 'lodash'
declare module 'lodash' {
type HasElements<T extends boolean> = T extends boolean ? { // distributive conditional, makes HasElements<boolean> == HasElements<true> | HasElements<false>
"gurad-traits"?: {
hasElements?: T
}
}: never
interface LoDashStatic {
isEmpty<T extends HasElements<boolean>>(value?: T): value is T & HasElements<false>;
last<T> (array: List<T> & HasElements<true>): T;
last<T> (array: (List<T> & HasElements<false> )| null | undefined): undefined;
}
}
function test<T>(array: T[] & _.HasElements<boolean>, defaultValue: T): T {
if (!_.isEmpty(array)) {
return _.last(array);
}else {
let u: T = _.last(array); /// err, returns undefined
return defaultValue;
}
}
test([1,2,3], 1); //HasElements does not influence the assignability of arrays
