如何在TypeScript的Record类型对象中自动实现类型收窄?
TypeScript 联合类型收窄与对象方法类型匹配问题
问题代码
enum ResourceType { A = 'a', B = 'b', } export type Resource = ResourceA | ResourceB export type ResourceA = { type: ResourceType.A name: "A" } export type ResourceB = { type: ResourceType.B, name: "B" } const elements: Record< ResourceType, (resource: Resource) => void > = { a: (resource: ResourceA) => ( console.log(resource) ), b: (resource: ResourceB) => ( console.log(resource) ) }
TypeScript 提示错误:Type '(resource: ResourceA) => void' is not assignable to type '(resource: Resource) => void',这是预期情况。
需求:希望根据与resource.type匹配的对象键自动收窄方法参数的类型,但一直未能实现。
解决方案
方法一:手动映射类型关联
先定义映射类型绑定ResourceType枚举值与对应Resource子类型,再用映射类型约束elements对象:
enum ResourceType { A = 'a', B = 'b', } export type ResourceA = { type: ResourceType.A name: "A" } export type ResourceB = { type: ResourceType.B, name: "B" } export type Resource = ResourceA | ResourceB // 建立枚举与子类型的映射关系 type ResourceMap = { [ResourceType.A]: ResourceA [ResourceType.B]: ResourceB } // 用映射类型定义elements的类型,自动匹配参数类型 const elements: { [K in ResourceType]: (resource: ResourceMap[K]) => void } = { a: (resource) => { console.log(resource) // 参数自动收窄为ResourceA }, b: (resource) => { console.log(resource) // 参数自动收窄为ResourceB } }
方法二:用Extract自动提取子类型
利用TypeScript内置的Extract类型,从联合类型中自动提取对应type的子类型,无需手动维护映射关系:
enum ResourceType { A = 'a', B = 'b', } export type ResourceA = { type: ResourceType.A name: "A" } export type ResourceB = { type: ResourceType.B, name: "B" } export type Resource = ResourceA | ResourceB // 从联合类型中提取指定type的子类型 type ResourceOfType<T extends ResourceType> = Extract<Resource, { type: T }> // 动态生成elements的类型约束 const elements: { [K in ResourceType]: (resource: ResourceOfType<K>) => void } = { a: (resource) => console.log(resource), // 参数为ResourceA b: (resource) => console.log(resource), // 参数为ResourceB }
这两种方式都能实现根据对象键自动收窄方法参数的类型,同时保证类型安全,后续新增Resource子类型时,只需扩展枚举和联合类型即可自动适配。
内容的提问来源于stack exchange,提问作者Baptiste Arnaud
相关产品推荐
相关产品推荐

