TypeScript 4.7.3中类型谓词在filter中返回类型异常问题
TypeScript 类型守卫在数组filter中的推导差异问题
使用自定义类型守卫过滤联合类型数组时,不同写法会得到完全不同的类型推导结果:
- 直接传入类型守卫函数的无点风格写法,能正确推导为收窄后的类型:
const onlyFish = animals.filter(isFish); // 推导结果:Fish[]
- 用箭头函数包装一层再调用类型守卫时,无法正确收窄类型,返回原联合类型数组:
const onlyFish2 = animals.filter(x => isFish(x)); // 推导结果:(Fish | Bird)[]
复现问题的完整代码:
type Fish = { variant: 'fish' } type Bird = { variant: 'bird' } const isFish = (animal: Fish | Bird): animal is Fish => animal.variant === 'fish'; const animals: ReadonlyArray<Fish | Bird> = [{ variant: 'fish' }, { variant: 'bird' }]; const onlyFish = animals.filter(isFish); // Fish[] const onlyFish2 = animals.filter(x => isFish(x)); // (Fish | Bird)[]
推导结果差异的核心原因
TypeScript 不会为箭头函数隐式推导类型谓词(type predicate) 类型:
- 直接传入
isFish时,TS可以直接读取到函数的完整签名:(animal: Fish | Bird) => animal is Fish,该签名匹配Array.filter的类型守卫重载,因此过滤后数组会被收窄为Fish[]。 - 用
x => isFish(x)包装后,TS只会将这个箭头函数的返回值推导为普通boolean类型,不会自动识别出返回值实际携带了x is Fish的类型守卫信息,因此只会匹配filter的普通回调重载,返回原数组的联合类型(Fish | Bird)[]。
无需显式标注变量类型的解决方法
为箭头函数显式声明返回值的类型谓词即可,TS会识别这是一个合法的类型守卫,自动完成类型收窄:
// 正确推导为 Fish[] const onlyFish2 = animals.filter((x): x is Fish => isFish(x));
这种写法兼容需要在回调中添加额外逻辑的场景,同时不会丢失类型安全性,也不需要手动给onlyFish2添加整体类型标注。
内容的提问来源于stack exchange,提问作者GibboK
相关产品推荐
相关产品推荐

