MSW Resolver装饰器类型错误:可分配类型但可能实例化为不同子类型
MSW Resolver装饰器的TypeScript类型错误问题
我想通过response composition装饰MSW的resolver并返回一个新的resolver,编写了如下代码:
import { ResponseResolver, context, createResponseComposition, response } from "msw"; export const createDelayedComposer = < M extends ResponseResolver<any, any, any> >( milliseconds: number ) => { const delayed = createResponseComposition(undefined, [ context.delay(milliseconds) ]); return (resolver: M): M => (req, _, ctx) => resolver(req, Object.assign(delayed, response), ctx); };
但出现了以下TypeScript错误:
Type '(req: any, _: ResponseComposition<any>, ctx: any) => AsyncResponseResolverReturnType<MockedResponse<any>>' is not assignable to type 'M'. '(req: any, _: ResponseComposition<any>, ctx: any) => AsyncResponseResolverReturnType<MockedResponse<any>>' is assignable to the constraint of type 'M', but 'M' could be instantiated with a different subtype of constraint 'ResponseResolver<any, any, any>'.ts(2322)
请问我的签名哪里出错了?该如何修复?或者是否有其他实现resolver装饰的方法?
错误原因
这个TypeScript错误的核心是泛型约束过宽且返回值类型不匹配:
- 你定义的泛型
M是ResponseResolver<any, any, any>的子类型,但返回的匿名函数只能匹配最宽泛的ResponseResolver<any, any, any>,无法保证和传入的具体M子类型完全兼容(比如M可能有更具体的请求/响应类型)。 - 直接将匿名函数断言为
M,TypeScript无法确认这个函数的结构和M的具体类型完全一致。
修复方案
需要更精确地拆分泛型参数,确保返回的resolver和传入的类型完全对齐:
import { ResponseResolver, context, createResponseComposition, response, ResponseComposition, DefaultBodyType, PathParams, RestRequest, } from "msw"; export const createDelayedComposer = < B extends DefaultBodyType = DefaultBodyType, P extends PathParams = PathParams, R extends ResponseComposition<B> = ResponseComposition<B> >( milliseconds: number ) => { const delayed = createResponseComposition<B>(undefined, [ context.delay(milliseconds), ]); // 合并response并保持类型一致 const enhancedResponse = Object.assign(delayed, response) as R; return (resolver: ResponseResolver<B, RestRequest<B, P>, R>): ResponseResolver<B, RestRequest<B, P>, R> => { return (req, res, ctx) => resolver(req, enhancedResponse, ctx); }; };
关键调整:
- 拆分
ResponseResolver的三个泛型参数(响应体、请求参数、响应组合体),让类型推导更精确。 - 显式指定
createResponseComposition的泛型类型B,确保响应体类型统一。 - 对合并后的
enhancedResponse做类型断言,匹配传入resolver期望的响应组合体类型。 - 返回的函数明确标注为和传入resolver完全一致的
ResponseResolver类型,消除类型不兼容问题。
替代实现:简洁的高阶函数包装
如果不需要极致的类型严谨性,可以用更简洁的方式实现,直接通过类型断言让TypeScript认可返回类型:
import { ResponseResolver, context, createResponseComposition, response, } from "msw"; export const withDelay = (milliseconds: number) => { const delayed = createResponseComposition(undefined, [ context.delay(milliseconds), ]); const enhancedResponse = Object.assign(delayed, response); return <T extends ResponseResolver<any, any, any>>(resolver: T): T => { return ((req, _, ctx) => resolver(req, enhancedResponse, ctx)) as T; }; };
这种写法代码更简洁,适合大多数场景,通过as T直接告知TypeScript返回的函数就是传入的resolver类型。
内容的提问来源于stack exchange,提问作者Adam Jenkins
相关产品推荐
相关产品推荐

