如何在对象中实现TypeScript类型守卫并返回附加信息?
带附加信息的TypeScript类型守卫实现方案
问题场景
我想实现带附加信息的类型守卫,尝试了以下代码,但TypeScript不允许把返回对象里的result设为anything is Something,只能设为boolean,想知道如何实现需求:
type Something = string | number; const isSomething = (anything: unknown): { result: anything is Something, additionalInfo: any } => { // ... 实现逻辑 } // 使用场景 const afterTypeGuard = isSomething(thing); if (afterTypeGuard.result === true) { return { info: afterTypeGuard.additionalInfo, length: thing.length, // 希望这里thing被推断为Something类型 } } else { return (thing + 32) * 3; // 希望这里thing被推断为非Something类型 }
可行解决方案
方案1:返回区分联合类型(Discriminated Union)
利用TypeScript的区分联合类型,用result作为区分符,让TS能根据它的true/false自动窄化输入参数的类型。
修改后的代码示例:
type Something = string | number; // 定义区分联合类型的返回结构 type IsSomethingResult<T> = | { result: true; additionalInfo: any; // result为true时,标记值为Something类型 value: T & Something } | { result: false; additionalInfo: any; // result为false时,标记值为非Something类型 value: Exclude<T, Something> }; const isSomething = <T>(anything: T): IsSomethingResult<T> => { // 类型判断逻辑示例 if (typeof anything === 'string' || typeof anything === 'number') { return { result: true, additionalInfo: `当前类型:${typeof anything}`, value: anything as T & Something }; } else { return { result: false, additionalInfo: `未知类型:${typeof anything}`, value: anything as Exclude<T, Something> }; } }; // 使用示例 const thing: unknown = 'hello'; const guardResult = isSomething(thing); if (guardResult.result) { // 这里guardResult.value会被推断为string | number console.log({ info: guardResult.additionalInfo, length: typeof guardResult.value === 'string' ? guardResult.value.length : '数值类型无length属性' }); } else { // 这里guardResult.value是排除Something后的类型 console.log(`非目标类型处理:${guardResult.value}`); }
方案2:通过参数传递附加信息容器
如果不想返回包含值的对象,可以用引用类型参数来存储附加信息,同时保留传统类型守卫的写法:
type Something = string | number; // 定义存储附加信息的容器接口 interface GuardMeta { additionalInfo?: any; } // 传统类型守卫函数,同时修改传入的meta对象存储附加信息 const isSomething = (anything: unknown, meta: GuardMeta): anything is Something => { if (typeof anything === 'string' || typeof anything === 'number') { meta.additionalInfo = `匹配类型:${typeof anything}`; return true; } else { meta.additionalInfo = `不匹配类型:${typeof anything}`; return false; } }; // 使用示例 const thing: unknown = 456; const meta: GuardMeta = {}; if (isSomething(thing, meta)) { console.log({ info: meta.additionalInfo, value: thing // 此处thing已被推断为string | number }); } else { console.log(`错误提示:${meta.additionalInfo}`); }
为什么原写法不生效?
TypeScript的类型谓词(比如anything is Something)只能直接作为函数的返回类型,不能作为对象属性的类型。这是因为类型守卫的逻辑依赖于函数返回值和参数之间的直接关联,对象属性无法触发TS的类型窄化机制。
内容的提问来源于stack exchange,提问作者CWYOO
相关产品推荐
相关产品推荐

