TypeScript泛型类中泛型Tag数组过滤类型收窄失败原因与解决方案
报错原因
TypeScript在处理泛型类型的收窄时,默认不会验证自定义类型守卫和泛型约束的兼容性,因为泛型T extends Tag的实际取值范围是所有满足Tag接口约束的类型:
- 既可以是
SimpleTag、CollectorTag,也可以是用户自定义的其他实现了Tag接口的类型 - TypeScript在编译泛型类逻辑时,只会基于泛型的最小约束做静态检查,不会代入运行时判断逻辑,因此不认可直接将泛型类型
T的变量通过类型守卫收窄为CollectorTag类型,也就不认为filter返回的结果可以赋值给CollectorTag[]。
外层非泛型代码可以正常运行,是因为参数是明确的Tag类型,CollectorTag是Tag的已知子类型,类型守卫的合法性可以被验证。
解决方案
有三种常用的处理方式:
方案1:调整泛型约束为已知的联合类型
如果确定Tag只有SimpleTag和CollectorTag两个子类型,可以直接把泛型约束改为这两个类型的联合,TypeScript就能正常识别类型守卫的合法性:
class CollectorDefinitionProcessor <T extends SimpleTag | CollectorTag> { process(definition: ServiceDefinition<T>): void { const collectorTags: CollectorTag[] = definition.tags.filter((t: T): t is CollectorTag => t.type === TagType.COLLECTOR); } }
方案2:将数组转换为基础Tag类型后过滤
复用外层正常代码的逻辑,先把泛型数组转成Tag[]再做过滤:
class CollectorDefinitionProcessor <T extends Tag> { process(definition: ServiceDefinition<T>): void { const collectorTags: CollectorTag[] = (definition.tags as Tag[]).filter((t: Tag): t is CollectorTag => t.type === TagType.COLLECTOR); } }
方案3:对过滤结果直接加类型断言
如果确定运行时判断逻辑没有问题,可以直接给filter的返回结果加类型断言跳过检查:
class CollectorDefinitionProcessor <T extends Tag> { process(definition: ServiceDefinition<T>): void { const collectorTags = definition.tags.filter((t: T) => t.type === TagType.COLLECTOR) as CollectorTag[]; } }
内容的提问来源于stack exchange,提问作者Łukasz Zaroda
相关产品推荐
相关产品推荐

