如何限制类仅包含string类型属性?(Express req.params场景)
问题描述
在Express中,req.params是一个仅包含string类型属性的对象,但默认类型被定义为Record<string, string>,实用性不足。我希望通过类定义来明确req.params的结构,同时借助class-validator实现运行时校验,于是编写了如下类型声明与使用示例:
declare function createRequestHandler<Params extends object>( paramsConstructor: new (...args: never) => Params, handler: express.RequestHandler<Params>, ): express.RequestHandler<Params>
class GetUserByIdParams { userId!: string } app.get('/users/:userId', createRequestHandler(GetUserByIdParams, (req) => { req.params.userId; // ✅ 类型校验通过 }))
但当前存在一个问题:参数类可以定义任意类型的属性(如number、boolean或复合对象),而这些类型在运行时的req.params中根本不可能存在。例如:
class InvalidParams { userId!: number } app.get('/users/:userId', createRequestHandler(InvalidParams, (req) => { req.params.userId.toFixed(2); // ❌ 运行时会报错,但编译阶段无提示 }))
虽然class-validator会在运行时抛出校验错误,但我希望在编译阶段就限制参数类只能包含string类型的属性,该如何实现?
解决方案
基础约束方案
直接修改createRequestHandler的泛型约束,将Params extends object替换为Params extends Record<string, string>,强制要求参数类的所有属性必须为string类型:
declare function createRequestHandler<Params extends Record<string, string>>( paramsConstructor: new (...args: never) => Params, handler: express.RequestHandler<Params>, ): express.RequestHandler<Params>
此时若参数类包含非string类型属性,TypeScript会直接在编译阶段报错:
class InvalidParams { userId!: number // ❌ 编译错误:类型“number”不能赋值给类型“string” } app.get('/users/:userId', createRequestHandler(InvalidParams, (req) => { // 此处会直接提示参数类型不匹配 }))
严格约束方案
如果需要更严格的校验(比如禁止隐式any类型、确保所有属性明确为string),可以自定义类型工具来强化约束:
// 类型工具:确保对象所有属性均为string类型,非string属性会被映射为never type StringOnlyObject<T> = { [K in keyof T]: T[K] extends string ? string : never; }; declare function createRequestHandler<Params extends StringOnlyObject<Params>>( paramsConstructor: new (...args: never) => Params, handler: express.RequestHandler<Params>, ): express.RequestHandler<Params>
这个工具会将非string类型的属性映射为never,只要参数类存在非string属性,就会触发类型不兼容错误,彻底在编译阶段杜绝这类问题。
内容的提问来源于stack exchange,提问作者Parzh
相关产品推荐
相关产品推荐

