TypeScript类型谓词返回false时推断为never类型的问题排查
问题原因与解决方案
核心问题
你的SourceWithMedia和SourceWithoutMedia接口不是互斥类型:SourceWithoutMedia的所有属性(仅id)完全包含在SourceWithMedia中,TypeScript会认为「只包含id的SourceWithMedia对象同时也属于SourceWithoutMedia类型」。
当你的类型守卫函数isSourceWithoutMedia返回false时,TypeScript找不到既属于联合类型又不属于SourceWithoutMedia的剩余类型,因此推断为never。
解决方法
方法1:使用区分联合类型(推荐)
给两个接口添加唯一的区分字段,让TypeScript能明确区分类型:
interface SourceWithMedia { type: 'with-media'; // 区分字段 id: string; someOtherProperty: string; media?: string; } interface SourceWithoutMedia { type: 'without-media'; // 区分字段 id: string; } const isSourceWithoutMedia = (source: SourceWithMedia | SourceWithoutMedia): source is SourceWithoutMedia => { return source.type === 'without-media'; } function doSomethingWithMedia(source: SourceWithMedia | SourceWithoutMedia) { if (isSourceWithoutMedia(source)) return source; if (source.media) return source.media; // 正确推断为SourceWithMedia类型 }
方法2:修改类型守卫的判断逻辑
直接检查SourceWithMedia特有的属性(比如someOtherProperty)是否存在,让TypeScript能准确收窄类型:
interface SourceWithMedia { id: string; someOtherProperty: string; media?: string; } interface SourceWithoutMedia { id: string; } const isSourceWithoutMedia = (source: SourceWithMedia | SourceWithoutMedia): source is SourceWithoutMedia => { return !('someOtherProperty' in source); } function doSomethingWithMedia(source: SourceWithMedia | SourceWithoutMedia) { if (isSourceWithoutMedia(source)) return source; if (source.media) return source.media; // 正确推断为SourceWithMedia类型 }
为什么原逻辑不行?
原代码用Object.keys(source).length === 1判断,本质是依赖运行时的属性数量,但TypeScript的类型系统基于结构兼容性:即使SourceWithMedia要求someOtherProperty必填,运行时仍可能存在只包含id的对象(比如绕过TypeScript检查的情况),TypeScript无法通过属性数量区分两个结构兼容的类型。
内容的提问来源于stack exchange,提问作者mruthh
相关产品推荐
相关产品推荐

