TypeScript类泛型兼容:如何保留原API新增泛型参数?
问题描述
给以下State类添加类型定义时触发了两个TypeScript错误:
class State<TLinks extends Record<string, any> = Record<string, any>> { async follow<TFollowResource = TLinks[TRel], TRel extends keyof TLinks>(rel: TRel): Promise<Resource<TFollowResource>> { // 测试用代码,忽略具体实现 return true as any; } }
错误信息:
Type parameter defaults can only reference previously declared type parameters.Required type parameters may not follow optional type parameters.
问题出在follow方法的泛型参数顺序:带默认值的TFollowResource依赖了后面才声明的TRel,而且必填的泛型参数(无默认值的TRel)放在了可选参数之后。
由于这是已有开源库,必须保留原有API的兼容性(旧代码不需要传入新增的TRel泛型参数),不能直接调换泛型参数顺序,因此需要兼容方案。
解决方案1:方法重载(兼容性最优)
通过定义两个重载签名,分别对应旧API(无需指定泛型)和新API(支持自定义类型),完美兼容新旧调用方式:
class State<TLinks extends Record<string, any> = Record<string, any>> { // 旧API重载:自动推导TRel和对应的资源类型 async follow<TRel extends keyof TLinks>(rel: TRel): Promise<Resource<TLinks[TRel]>>; // 新API重载:允许自定义资源类型 async follow<TFollowResource, TRel extends keyof TLinks>(rel: TRel): Promise<Resource<TFollowResource>>; // 统一实现体 async follow<TRel extends keyof TLinks, TFollowResource = TLinks[TRel]>(rel: TRel): Promise<Resource<TFollowResource>> { return true as any; } }
旧代码调用state.follow("user")时,会自动推导TRel为"user",TFollowResource为TLinks["user"];新代码如果需要自定义资源类型,可以写成state.follow<CustomUserType, "user">("user"),完全不破坏原有使用方式。
解决方案2:泛型参数+辅助推导参数
调换泛型参数顺序的同时,增加一个不影响运行时的可选辅助参数,让旧代码无需手动指定泛型:
class State<TLinks extends Record<string, any> = Record<string, any>> { async follow<TRel extends keyof TLinks, TFollowResource = TLinks[TRel]>( rel: TRel, // 仅用于类型推导,运行时可以不传 _resourceHint?: TFollowResource ): Promise<Resource<TFollowResource>> { return true as any; } }
旧代码调用state.follow("user")时,TypeScript会自动推导TRel并使用默认的TFollowResource;如果需要自定义资源类型,可以通过state.follow("user", {} as CustomUserType)或者显式指定泛型state.follow<"user", CustomUserType>("user")实现需求。
内容的提问来源于stack exchange,提问作者Evert
相关产品推荐
相关产品推荐

