TypeScript函数能否返回自定义类型守卫?TS2322报错原因是什么
为什么编译器会报错?
这是TypeScript当前版本的设计限制:
只有两种场景TS会自动将函数识别为带类型谓词的类型守卫:
- 你直接为函数本身显式标注了返回类型为
参数名 is 类型的类型谓词 - 函数是写在
if条件判断、Array.filter入参等位置的内联匿名函数,TS做了特殊的窄化适配
你代码中返回的内层箭头函数没有单独标注类型谓词,TS不会主动结合外层函数的返回类型约束去推导它的返回值是类型谓词,只会默认把它当成返回boolean的普通函数,自然和外层要求的(x: any) => x is AnimalFromType<T>类型不匹配,抛出TS2322错误。
可行的实现方案
你只需要给返回的箭头函数显式加上类型谓词标注即可,推荐写法如下,同时把入参any换成更安全的unknown:
interface Animal { type: string; } interface Dog extends Animal { type: 'dog'; sound: 'bark'; } interface Cat extends Animal { type: 'cat'; purpose: 'world_domination'; } type Animals = Dog | Cat; type AnimalFromType<T extends Animals['type']> = Extract<Animals, { type: T }>; function createFilter<T extends Animals['type']>(type: T): (x: unknown) => x is AnimalFromType<T> { // 给内层箭头函数显式标注返回类型为类型谓词 return (x: unknown): x is AnimalFromType<T> => { return typeof x === 'object' && x !== null && 'type' in x && x.type === type; }; }
使用效果
const animals: Animals[] = [ { type: 'dog', sound: 'bark' }, { type: 'cat', purpose: 'world_domination' }, { type: 'dog', sound: 'bark' } ]; // 过滤后dogs自动推导为Dog[]类型 const dogs = animals.filter(createFilter('dog')); dogs.forEach(dog => console.log(dog.sound)); // 过滤后cats自动推导为Cat[]类型 const cats = animals.filter(createFilter('cat')); cats.forEach(cat => console.log(cat.purpose));
如果你的逻辑确定安全,也可以用类型断言简化写法:
function createFilter<T extends Animals['type']>(type: T): (x: unknown) => x is AnimalFromType<T> { return x => typeof x === 'object' && x !== null && 'type' in x && x.type === type as (x: unknown) => x is AnimalFromType<T>; }
内容的提问来源于stack exchange,提问作者JHH
相关产品推荐
相关产品推荐

