TypeScript字段映射类型声明:如何解决doThing生成函数类型不兼容报错
问题原因
TS 无法自动将泛型参数 T 对应的 { type: T, parameters: SpecParametersMap[T] } 结构关联到 UserSpec | ClientSpec 联合类型,因为 TS 不会默认遍历泛型的所有可能取值做类型匹配。
解决方案
你可以根据是否需要重构类型选择任意一种方案:
方案1:最小改动(不重构现有类型)
直接给报错的结构加安全的类型断言即可,你的逻辑已经保证了 type 和 parameters 是匹配的,断言不会引入安全问题:
export const doThing = <T extends SpecType>( type: T, parameters: SpecParametersMap[T] ): void => { const account: AccountDefinition = { foo: { type: 'client', parameters: { foo: 3 } }, // 加类型断言即可解决报错 data: { parameters, type } as UserSpec | ClientSpec } }
方案2:重构类型获得更好的类型体验
把 Spec 从接口改为自动分发的联合类型,后续做类型收窄会更方便,同时可以用函数重载避免使用者手动传泛型:
export enum SpecType { USER = 'user', CLIENT = 'client' } export interface UserSpecParameters { bar?: number } export interface ClientSpecParameters { foo: number } export type SpecParametersMap = { [SpecType.USER]: UserSpecParameters [SpecType.CLIENT]: ClientSpecParameters } // 自动分发的Spec联合类型,不需要再单独定义UserSpec、ClientSpec export type Spec<T extends SpecType = SpecType> = T extends any ? { type: T parameters: SpecParametersMap[T] } : never export interface AccountDefinition { [k: string]: Spec } // 函数重载,自动根据入参type推断parameters类型,不需要使用者传泛型 export function doThing(type: SpecType.USER, parameters: UserSpecParameters): void export function doThing(type: SpecType.CLIENT, parameters: ClientSpecParameters): void export function doThing(type: SpecType, parameters: SpecParametersMap[SpecType]): void { const account: AccountDefinition = { foo: { type: SpecType.CLIENT, parameters: { foo: 3 } }, data: { parameters, type } as Spec } } // 调用时自动推断类型,传错参数会直接报错 doThing(SpecType.CLIENT, { foo: 4 })
两种方案都可以解决你遇到的类型报错问题,方案2后续维护的类型体验会更好。
内容的提问来源于stack exchange,提问作者cyberwombat
相关产品推荐
相关产品推荐

