如何动态创建路由?
How to dynamically create routes?
我正在尝试通过遍历称为路由组的对象数组来向我的 api 动态添加路由。一个路由组可以有多个路由。
这是我的类型(RouterContext 类型来自 Oak 中间件框架):
// routes/mod.ts
type Route = {
method: string;
path: string;
handler: (ctx: RouterContext) => Promise<void>;
};
export type RouteGroup = {
group: {
prefix: string;
};
routes: Route[];
};
这是我的路由器 class:
export class Router {
// imported Oak's Router class as oakRouter
router: oakRouter;
constructor() {
this.router = new oakRouter({ prefix: "/api" });
}
register(): void {
this._createRoutes(routeGroups);
}
private _createRoutes(routeGroups: RouteGroup[]) {
routeGroups.forEach(({ group, routes }) => {
routes.forEach(({ method, path, handler }) => {
this.router[method](group.prefix + path, handler); // <-- this.router[method] is underlined with an error
});
});
}
}
典型的路线如下所示:
router.get("/", (ctx) => {
ctx.response.body = "Welcome to My Oak App.";
});
但是当我使用括号表示法在_createRoutes()中动态添加我想使用的http方法时,出现以下错误:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Router<RouteParams, Record<string, any>>'.
No index signature with a parameter of type 'string' was found on type 'Router<RouteParams, Record<string, any>>'.deno-ts(7053)
如何将 Route 类型的方法 属性 从字符串更改为有效的索引签名?这就是我需要做的吗?
最简单且类型安全性最低的方法是将路由器函数转换为 any
如果您确信自己比 TypeScript 编译器更了解:
(this.router[method] as any)(group.prefix + path, handler);
或
(<any>this.router[method])(group.prefix + path, handler);
这绕过了很多类型检查,这通常不是我们想要的。
另一种方法是为 Oak Router
支持的每个方法使用类型保护(例如通过 switch
语句),它是类型安全的但确实重复了一些代码:
const args = [group.prefix + path, handler] as const;
switch (method) {
case "all":
this.router[method](...args);
break;
case "delete":
this.router[method](...args);
break;
case "get":
this.router[method](...args);
break;
case "head":
this.router[method](...args);
break;
case "options":
this.router[method](...args);
break;
case "patch":
this.router[method](...args);
break;
case "post":
this.router[method](...args);
break;
case "put":
this.router[method](...args);
break;
}
第三个选项是在 Route.method
中枚举支持的方法函数名称,然后告诉 TypeScript 编译器将所有函数视为相同的函数类型(选择任何函数名称,例如 get
):
type Route = {
method:
| "all"
| "delete"
| "get"
| "head"
| "options"
| "patch"
| "post"
| "put";
path: string;
handler: (ctx: RouterContext) => Promise<void>;
};
然后在_createRoutes
里面:
(this.router[method] as oakRouter["get"])(group.prefix + path, handler);
这比第一种方法更类型安全,但不如第二种方法类型安全。
P.S。我建议将 oakRouter
重命名为 OakRouter
。 Class 和类型名称通常以 JavaScript/TypeScript.
中的大写字母开头
我正在尝试通过遍历称为路由组的对象数组来向我的 api 动态添加路由。一个路由组可以有多个路由。
这是我的类型(RouterContext 类型来自 Oak 中间件框架):
// routes/mod.ts
type Route = {
method: string;
path: string;
handler: (ctx: RouterContext) => Promise<void>;
};
export type RouteGroup = {
group: {
prefix: string;
};
routes: Route[];
};
这是我的路由器 class:
export class Router {
// imported Oak's Router class as oakRouter
router: oakRouter;
constructor() {
this.router = new oakRouter({ prefix: "/api" });
}
register(): void {
this._createRoutes(routeGroups);
}
private _createRoutes(routeGroups: RouteGroup[]) {
routeGroups.forEach(({ group, routes }) => {
routes.forEach(({ method, path, handler }) => {
this.router[method](group.prefix + path, handler); // <-- this.router[method] is underlined with an error
});
});
}
}
典型的路线如下所示:
router.get("/", (ctx) => {
ctx.response.body = "Welcome to My Oak App.";
});
但是当我使用括号表示法在_createRoutes()中动态添加我想使用的http方法时,出现以下错误:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Router<RouteParams, Record<string, any>>'.
No index signature with a parameter of type 'string' was found on type 'Router<RouteParams, Record<string, any>>'.deno-ts(7053)
如何将 Route 类型的方法 属性 从字符串更改为有效的索引签名?这就是我需要做的吗?
最简单且类型安全性最低的方法是将路由器函数转换为 any
如果您确信自己比 TypeScript 编译器更了解:
(this.router[method] as any)(group.prefix + path, handler);
或
(<any>this.router[method])(group.prefix + path, handler);
这绕过了很多类型检查,这通常不是我们想要的。
另一种方法是为 Oak Router
支持的每个方法使用类型保护(例如通过 switch
语句),它是类型安全的但确实重复了一些代码:
const args = [group.prefix + path, handler] as const;
switch (method) {
case "all":
this.router[method](...args);
break;
case "delete":
this.router[method](...args);
break;
case "get":
this.router[method](...args);
break;
case "head":
this.router[method](...args);
break;
case "options":
this.router[method](...args);
break;
case "patch":
this.router[method](...args);
break;
case "post":
this.router[method](...args);
break;
case "put":
this.router[method](...args);
break;
}
第三个选项是在 Route.method
中枚举支持的方法函数名称,然后告诉 TypeScript 编译器将所有函数视为相同的函数类型(选择任何函数名称,例如 get
):
type Route = {
method:
| "all"
| "delete"
| "get"
| "head"
| "options"
| "patch"
| "post"
| "put";
path: string;
handler: (ctx: RouterContext) => Promise<void>;
};
然后在_createRoutes
里面:
(this.router[method] as oakRouter["get"])(group.prefix + path, handler);
这比第一种方法更类型安全,但不如第二种方法类型安全。
P.S。我建议将 oakRouter
重命名为 OakRouter
。 Class 和类型名称通常以 JavaScript/TypeScript.