能否使用Type Guard收窄TypeScript泛型类型?
Type Guard收窄泛型类型时的自动补全问题
我尝试使用Type Guard收窄泛型类型,期望自动补全能识别已触发Type Guard,不再进入重复代码块。我猜测原因是未对泛型进行类型约束,但不确定具体实现方式,想确认是否可行,恳请提供帮助。
// 定义类型结构 export type Feature<Geometry> = { type: 'Feature', geometry: Geometry } type Geometry = Point | Curve interface Base { type: string } interface Point extends Base{ type: 'Point' } interface Curve extends Base { type: 'Curve' } // Geometry类型守卫 function isGeometry<G extends Geometry, U extends G['type']>(geometry: G, disciminator: U): geometry is Extract<G, {type: U}> { return geometry.type === disciminator } // 原存在问题的Feature类型守卫 function isFeature<G extends Geometry, U extends G['type']>(feature: Feature<G>, disciminator: U): feature is Feature<Extract<G, {type: U}>> { return feature.geometry.type === disciminator } // 正常工作的类型收窄示例 function whatGeometry(feature: Feature<Point | Curve>) { if(isGeometry(feature.geometry, 'Curve')){ return feature.geometry; // ^? 类型自动收窄为Curve } if(isGeometry(feature.geometry, 'Point')){ return feature.geometry; // ^? 类型自动收窄为Point } // TypeScript能识别已无剩余类型,不会提示重复分支 return; } // 存在类型收窄问题的示例 function whatFeature(feature: Feature<Point | Curve>) { if(isFeature(feature, 'Curve')){ return feature.geometry; // ^? 类型自动收窄为Curve } if(isFeature(feature, 'Point')) { return feature; // ^? 仍被识别为Feature<Point | Curve>,未正确收窄 } // TypeScript错误认为还有剩余的Feature<Point>类型 return; }
问题原因及解决方法
问题出在isFeature的泛型约束逻辑:原写法中U extends G['type'],当G是联合类型Point | Curve时,G['type']会被推断为'Point' | 'Curve',但TypeScript无法在类型守卫中正确追踪联合类型的剩余分支。
调整isFeature的泛型定义,让U直接约束为Geometry['type'],确保类型守卫能准确收窄Feature的子类型:
function isFeature<U extends Geometry['type']>( feature: Feature<Geometry>, discriminator: U ): feature is Feature<Extract<Geometry, { type: U }>> { return feature.geometry.type === discriminator; }
如果需要保留对任意G extends Geometry的泛型支持,也可以调整约束方式:
function isFeature<G extends Geometry, U extends Geometry['type']>( feature: Feature<G>, discriminator: U ): feature is Feature<Extract<G, { type: U }>> { return feature.geometry.type === discriminator; }
调整后,whatFeature函数的类型收窄会正常工作:
- 第一个
if块执行后,剩余的feature会自动收窄为Feature<Point> - 第二个
if块中返回的feature会被正确识别为Feature<Point> - 最终TypeScript会确认已无剩余类型,不会提示重复代码分支
内容的提问来源于stack exchange,提问作者Martin Hansson
相关产品推荐
相关产品推荐

