typescript 是不是能够理解数组是不是为非空并相应地推断某些数组方法的类型?
Posted
技术标签:
【中文标题】typescript 是不是能够理解数组是不是为非空并相应地推断某些数组方法的类型?【英文标题】:Could typescript be able to understand whether an array is non-empty and infer types of some array methods accordingly?typescript 是否能够理解数组是否为非空并相应地推断某些数组方法的类型? 【发布时间】:2019-09-21 20:59:10 【问题描述】:我最近更新了 typescript 和 lodash,现在编译器明白了,例如如果数组非空,_.last()
之类的方法将返回一个值,如果数组为空,则返回 undefined。这是预期的行为,尤其是当我们不知道数组是否为空时。
但是,在诸如调用_.last([1,2,3])
的情况下,我们只知道该数组是非空的,这将始终返回一个数字。此外,我在代码中有几个地方检查了非空,并采取了相应的行动,例如:
if (!_.isEmpty(array))
return _.last(array);
... 通过查看该代码,我们知道该语句将返回一个元素,该元素具有该数组中元素的类型。但是返回类型仍然是T | undefined
。
我知道我可以在这种情况下转换值。但我宁愿避免投射东西。
所以我的问题是:打字稿有可能理解这样的情况吗?
【问题讨论】:
【参考方案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
【讨论】:
有趣。感谢分享! @Timzai 不确定它是否有用,我们可以在类型系统中做很多杂技并不意味着我们总是应该这样做。您决定是否值得麻烦:)。如果您最终使用其中任何一个并且有任何其他问题,请告诉我,这是一个非常有趣的话题:) 我可能最终不会使用它,因为我需要将扩展类型添加到很多地方,这是该产品的开发人员需要记住的事情,所以不好。因此,我希望这将来自打字稿语言或 linter。但是你的回答拓宽了我的思路,所以在这个意义上它很有用:)以上是关于typescript 是不是能够理解数组是不是为非空并相应地推断某些数组方法的类型?的主要内容,如果未能解决你的问题,请参考以下文章
Angular 2 / Typescript - 如何检查对象数组以查看属性是不是具有相同的值?
React useContext & Typescript:不是数组类型
sequelize/sequelize-typescript - 带有 HasMany 的 findAll 返回一个对象而不是数组