TypeScript类型折叠导致启用中间件时Body类型丢失的问题求助
TypeScript类型折叠导致启用中间件时Body类型丢失的问题求助
我最近在开发轻量级路由框架的TypeScript类型定义时,遇到了一个非常困惑的问题:当给路由配置添加middleware数组后,请求上下文的body类型会直接丢失,但移除middleware配置后,类型推断又能完全正常工作。
具体现象如下:
- 同时配置
body和middleware时,TypeScript会报错提示ctx.body属性不存在 - 仅配置
body时,ctx.body能被正确推断为对应的业务类型(比如示例中的{ hello: string })
我怀疑这是TypeScript的类型折叠(Type Collapsing)机制导致的,但始终搞不清楚具体触发原因和解决办法。以下是可复现的完整代码:
interface Schema<T> { t: T } declare const s: Schema<{ hello: string }> interface BaseContext { readonly request: any } type Middleware = (context: BaseContext, next: () => Middleware) => any interface RouteOptions { readonly body?: any; readonly middleware?: Middleware[]; } type SpecifyContext<C extends BaseContext, O extends RouteOptions> = { readonly [K in keyof C]: K extends 'request' ? any : C[K] } & (O['body'] extends Schema<infer T> ? { body: T } : {}); type RouteHandler<C extends BaseContext, O extends RouteOptions> = (context: SpecifyContext<C, O>) => any; class Mini { get<const O extends RouteOptions>( path: string, handler: RouteHandler<BaseContext, O>, options?: O ): Mini { return this; } } const mini = new Mini(); // 此处报错:Property 'body' does not exist on type 'SpecifyContext<BaseContext, { readonly body: Schema<{ hello: string; }>; readonly middleware: [(ctx: BaseContext, next: () => Middleware) => Middleware]; }>'. mini.get('/example', ctx => ctx.body, { body: s, middleware: [(ctx, next) => next()], } as const, ); // 此处完全正常,ctx.body被正确推断为{ hello: string } mini.get('/example', ctx => ctx.body, { body: s } as const, );
我观察到的关键类型差异:
- 添加
middleware时,泛型O被推断为{ readonly body: Schema<{ hello: string; }>; readonly middleware: [(ctx: BaseContext, next: () => Middleware) => Middleware]; },但SpecifyContext的条件类型分支没有被正确触发,没有合并{ body: { hello: string } }的类型 - 仅配置
body时,泛型O的类型是{ readonly body: Schema<{ hello: string; }>; },SpecifyContext能成功合并业务类型
我尝试过调整交叉结构、修改泛型约束,但都没能解决问题。想请教各位大佬:
- 这个类型丢失的根本原因是什么?是不是
Middleware类型与as const断言的组合触发了TypeScript的类型折叠? - 如何修改类型定义,才能让启用
middleware时也能正确推断出ctx.body的类型?
内容来源于stack exchange
相关产品推荐
相关产品推荐

