TypeScript中动态调用koa router方法出现类型错误如何解决
解决方案
错误1:动态调用router实例方法类型报错
原因
keyof typeof Router取的是Router类的静态成员类型,而instance是Router的实例对象,二者类型不匹配- Config接口中
method定义为string类型范围过宽,无法匹配koa router实例上仅有的几个HTTP方法名
解决方式
- 新增HTTP方法联合类型,缩小Config.method的类型范围
- 将方法名断言为Router实例的key类型,同时增加运行时校验避免非法方法调用
错误2:lastHandler可能为undefined报错
原因
Array.pop()在数组为空时会返回undefined,TS的严格模式下不允许调用可能为undefined的值
解决方式
提前判断lastHandler是否存在,业务上确保每个路由配置至少有一个处理函数的前提下也可以用非空断言!简化写法
额外优化
原代码中app.use(instance.routes()).use(instance.allowedMethods())写在routes的循环内,会导致同一个router实例被重复挂载,建议移到循环外部
完整修改后代码
import glob from "glob"; import Router from 'koa-router' import Application, {BaseContext, Next} from "koa"; // 新增合法HTTP方法类型 export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head' export interface Config { method: HttpMethod // 替换原string类型 route: string handlers: Array<(ctx: BaseContext, next?: Next) => Promise<void>> } export default (app: Application) => { glob(`${__dirname}/*`, { ignore: "**/index.js" }, (err, matches) => { if (err) { throw err; } matches.forEach((mod) => { const router = require(`${mod}/router`); const routes = router.default; const baseUrl = router.baseUrl; const instance = new Router({ prefix: baseUrl }); routes.forEach((config: Config) => { const { method = "", route = "", handlers = [] } = config; const lastHandler = handlers.pop(); // 校验处理函数存在 if (!lastHandler) { throw new Error(`路由${route}未配置处理函数`) } // 转为实例key类型 const routeMethod = method.toLowerCase() as keyof Router // 校验方法合法 if (typeof instance[routeMethod] !== 'function') { throw new Error(`不支持的路由方法:${method}`) } instance[routeMethod](route, ...handlers, async function (ctx: BaseContext) { return await lastHandler(ctx); } ); }); // 移到循环外,每个router实例只挂载一次 app.use(instance.routes()).use(instance.allowedMethods()); }); }); };
如果你的业务场景能100%确保method是合法值、handlers数组至少有一个元素,也可以用类型断言简化校验逻辑,省略运行时判断:
const lastHandler = handlers.pop()! instance[method.toLowerCase() as keyof Router](route, ...handlers, async (ctx: BaseContext) => { return await lastHandler(ctx) })
内容的提问来源于stack exchange,提问作者Quesofat
相关产品推荐
相关产品推荐

