为何TypeScript调用检查函数后仍不识别变量为数组?
问题描述
我编写了一个检查数组长度的简单函数:
export const hasLength = (arr?: unknown[]) => { const isArray = Array.isArray(arr); return isArray && arr.length !== 0; };
我原本期望调用该函数后,TypeScript能识别变量为非空数组,但实际并未实现。当前使用代码如下:
{hasLength(auction.bids) && ( <div> {[...auction.bids].reverse().map((bid) => null)} </div> )}
出现错误:Type 'string[] | undefined' is not an array type or does not have a '[Symbol.iterator]()' method that returns an iterator.ts
请问这是预期行为吗?如果是,原因是什么?
回答
这是预期行为,核心原因是:TypeScript无法自动推断普通函数的返回值和参数类型之间的关联,你的hasLength目前只是个返回布尔值的普通函数,没有被标记为类型守卫。
TypeScript的类型缩小(比如if (Array.isArray(arr)))只对内置的类型检查逻辑、或者明确声明了**类型谓词(type predicate)**的函数生效。你当前的函数虽然内部做了数组存在性和非空判断,但TypeScript不知道返回true时,参数arr一定是个非空数组——它只会把函数当成普通的布尔返回值,不会关联到参数的类型变化。
要让TypeScript识别这个函数的类型守卫作用,你需要修改函数的返回类型,用类型谓词明确告知TS:当函数返回true时,输入的arr是一个非空数组:
// 通用版本,适用于任意数组类型 export const hasLength = (arr?: unknown[]): arr is unknown[] => { return Array.isArray(arr) && arr.length !== 0; };
如果你的auction.bids明确是string[] | undefined类型,还可以把函数写得更精准:
// 针对string数组的专用版本 export const hasLength = (arr?: string[]): arr is string[] => { return Array.isArray(arr) && arr.length !== 0; };
修改后,当hasLength(auction.bids)为true时,TypeScript会自动将auction.bids的类型缩小为非空的string[],之前的迭代错误就会消失。
内容的提问来源于stack exchange,提问作者minlare

