如何用泛型简化TypeScript中stackPlayer函数的复杂参数类型?
简化Express中间件栈的TypeScript类型定义
我定义了如下函数:
function stackPlayer(stack){ }
其中stack参数仅允许为以下类型之一:
- 接收
req、res、next作为参数的函数; - 接收
req、res、next作为参数,且返回同样接收这三个参数的函数的函数; - 接收
req、res、next作为参数,且返回由上述函数组成的数组的函数; - 由上述函数组成的数组。
实际示例:
// 以下均可作为参数传入: (req, res, next) => {} // 或 (req, res, next) => (req, res, next) => {} // 或 (req,res,sNext) => [(req,res,sNext)=>{}] // 或 [(req,res,sNext)=>{}]
为了给该函数参数添加类型,我编写了如下可读性较差的复杂类型:
type Stack = | ((req: Request, res: Response, next: NextFunction) => {}) | (( req: Request, res: Response, next: NextFunction ) => (req: Request, res: Response, next: NextFunction) => {}) | (( req: Request, res: Response, next: NextFunction ) => { (req: Request, res: Response, next: NextFunction): void }[]) | { (req: Request, res: Response, next: NextFunction): void }[] function stackPlayer(stack: Stack){ }
我尝试用泛型简化但未成功:
type Smiddleware = <T = void>(req: Request, res: Response, next: NextFunction) => T type Stack = Smiddleware<void> | Smiddleware<Smiddleware> | Smiddleware<Smiddleware[]> | Smiddleware[]
求可行的简化方案。
解决方案
方案1:拆分基础类型复用
先定义最基础的中间件类型,再基于它扩展出其他需要的类型,结构清晰易读:
import { Request, Response, NextFunction } from 'express'; // 基础中间件:接收req/res/next,返回void type BaseMiddleware = (req: Request, res: Response, next: NextFunction) => void; // 返回单个中间件的函数 type MiddlewareReturningMiddleware = (req: Request, res: Response, next: NextFunction) => BaseMiddleware; // 返回中间件数组的函数 type MiddlewareReturningArray = (req: Request, res: Response, next: NextFunction) => BaseMiddleware[]; // 最终组合的Stack类型 type Stack = BaseMiddleware | MiddlewareReturningMiddleware | MiddlewareReturningArray | BaseMiddleware[];
方案2:泛型类型统一复用
如果你倾向于用泛型实现复用,需要把泛型参数定义在类型别名层面(而非函数层面),修正后的写法如下:
import { Request, Response, NextFunction } from 'express'; // 泛型中间件类型:接收req/res/next,返回指定类型T type GenericMiddleware<T = void> = (req: Request, res: Response, next: NextFunction) => T; // 基于泛型组合Stack类型 type Stack = | GenericMiddleware<void> | GenericMiddleware<GenericMiddleware<void>> | GenericMiddleware<GenericMiddleware<void>[]> | GenericMiddleware<void>[];
你之前的泛型写法失效,是因为把Smiddleware定义成了泛型函数类型,而不是接收泛型参数的类型别名。上面的写法将泛型参数绑定到类型别名上,就能正确实现类型复用了。
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

