如何使用TypeScript将输入JSON对象强制转换为Node.JS中的模型类?

如何使用TypeScript将输入JSON对象强制转换为Node.JS中的模型类?,node.js,typescript,express,Node.js,Typescript,Express,我正在使用TypeScript和express framework编写Node.js服务器。 这就是我的控制器和路由的外观: export class AuthController { public async signUpNewUser(request: Request, response: Response) { ... } } 如何接收模型类而不是ASP.NET中的请求类型? 比如: public async signUpNewUser(in

我正在使用TypeScript和express framework编写Node.js服务器。 这就是我的控制器和路由的外观:

  export class AuthController {

        public async signUpNewUser(request: Request, response: Response) {
        ...
    }
}
如何接收模型类而不是ASP.NET中的请求类型? 比如:

public async signUpNewUser(input: SignUpModel, response: Response) {
这是个好主意吗?我不确定这是Node.JS中的常用方法 我只是想确保每次都得到相同的模型,并编写与此模型相关的代码,而不是在动态JSON对象上

我的建议是在路线开始时转换为强类型模型,但我不确定这是一个好方法


有人有解决这种情况的办法吗?

所以你似乎有几个不同的问题。核心问题是“如何将JSON对象强制转换为特定类型”,但您也会问这是否是一个好主意,以及这是否是一种常见做法

第一个问题的答案很简单,你可以在你的路线(或任何地方)投下它,就像这样:

现在,你的其他问题更加基于观点。如果我是诚实的,我会说“不要使用打字脚本”。)别开玩笑了,我不知道如何回答你基于意见的问题(也不适合这个网站)

如何接收模型类而不是ASP.NET中的请求类型

在我的项目中(以及在工作中),这对我来说是一个永久的痛苦,最终我们决定用自己的默认错误处理和身份验证头检查来构建一个自定义路由器。这个模式的诀窍是保持它的轻量级,因为这仍然是express,中间件才是事情应该去的地方——这个包装器只是为我们提供了一种方法,根据我们实际使用的中间件,将express请求转换成一种适当形状的类型

这是一个简化的示例,其思想是您可以通过传递接口(或内联类型形状)来指定req&res的形状,并让typescript强制执行返回形状

包装类示例:

import * as express from 'express';

export type ExpressMethods = "get" | "post" | "put" | "delete" | "patch";

export type JsonRouteInput<RequestBody, RouteParams, QueryParams> = {
  body: RequestBody;
  params: RouteParams;
  query: QueryParams;
};

export type JsonRouteHandler<
  RequestBody,
  RouteParams,
  QueryParams,
  ResponseBody
> = (
  request: JsonRouteInput<RequestBody, RouteParams, QueryParams>
) => Promise<ResponseBody> | ResponseBody;

export class JsonRouter {
  router = express.Router();
  private addHandler<M extends ExpressMethods>(
    method: M,
    ...middleware: express.RequestHandler[]
  ) {
    this.router.use(...middleware);
  }

  get route(): {
    [K in ExpressMethods]: <
      RequestBody,
      ResponseBody,
      RouteParams = never,
      QueryParams = never
    >(
      path: string,
      handler: JsonRouteHandler<
        RequestBody,
        RouteParams,
        QueryParams,
        ResponseBody
      >
    ) => JsonRouter
  } {
    const addables = {} as any;
    (["get", "post", "put", "delete", "patch"] as ExpressMethods[]).forEach(
      <RequestBody, ResponseBody, RouteParams = never, QueryParams = never>(
        method
      ) => {
        addables[method] = (
          path: string,
          handler: JsonRouteHandler<
            RequestBody,
            RouteParams,
            QueryParams,
            ResponseBody
          >
        ) => {
          this.router[method](path, async (req, res) => {
            try {
              const responseBody: ResponseBody = await handler({
                body: req.body,
                params: req.params,
                query: req.query
              });
              res.json(responseBody);
            } catch (err) {
              // do your standard error handling or whatever
              res.status(500).end("ow");
            }
          });
          return this;
        };
      }
    );
    return addables;
  }
}

谢谢你的回答。我是否正确理解这不是常用的方法?对我来说,这种方法看起来更安全,这有意义吗?这种方法会有什么问题?我将把所有的功能移到有接口的类中,我想使用DI模式,所以我将用输入模型类型的方法编写接口,就像route一样。这就是为什么我需要这个,我不能代表整个社区,但是考虑到npm上大多数模块中几乎所有的nodejs文档都是为JavaScript编写的,而不是为TypeScript编写的,我认为这可能并不常见。至于它怎么了?我并不是说这本身就是错误的,但从C#到node.js(JavaScript),我可以说,在过去9年中,我从未错过过强大的键入功能。看看另一个答案,这看起来确实需要维护更多的代码。@neustart47这是一个主要的痛点:)。在大多数项目中,除了API和UI之间的契约之外,一切都是类型安全的,并且工作得很好。我们(所有的程序员)都因此遭受了无数的错误。只有一个小问题:我刚从node.js开始,我不确定我是否理解如何用您的示例声明路由。我正在声明我在本主题开头描述的路线。我应该在哪里粘贴您的代码和使用示例?也许,你有一些回购的例子或任何类型的主题与教程?我从express开始,这个声明对我来说是新的。Thanks@neustart47用一个例子更新了答案。您可以使用
use
在路径下装载路由器。路由器本身也可以
使用
其他路由器-这提供了很大的灵活性-例如,您可以有条件地添加中间件,在
/admin
下为一组端点授权用户,例如
app.use('/admin',adminAuthMiddleware,adminExpressRouter)
import * as express from 'express';

export type ExpressMethods = "get" | "post" | "put" | "delete" | "patch";

export type JsonRouteInput<RequestBody, RouteParams, QueryParams> = {
  body: RequestBody;
  params: RouteParams;
  query: QueryParams;
};

export type JsonRouteHandler<
  RequestBody,
  RouteParams,
  QueryParams,
  ResponseBody
> = (
  request: JsonRouteInput<RequestBody, RouteParams, QueryParams>
) => Promise<ResponseBody> | ResponseBody;

export class JsonRouter {
  router = express.Router();
  private addHandler<M extends ExpressMethods>(
    method: M,
    ...middleware: express.RequestHandler[]
  ) {
    this.router.use(...middleware);
  }

  get route(): {
    [K in ExpressMethods]: <
      RequestBody,
      ResponseBody,
      RouteParams = never,
      QueryParams = never
    >(
      path: string,
      handler: JsonRouteHandler<
        RequestBody,
        RouteParams,
        QueryParams,
        ResponseBody
      >
    ) => JsonRouter
  } {
    const addables = {} as any;
    (["get", "post", "put", "delete", "patch"] as ExpressMethods[]).forEach(
      <RequestBody, ResponseBody, RouteParams = never, QueryParams = never>(
        method
      ) => {
        addables[method] = (
          path: string,
          handler: JsonRouteHandler<
            RequestBody,
            RouteParams,
            QueryParams,
            ResponseBody
          >
        ) => {
          this.router[method](path, async (req, res) => {
            try {
              const responseBody: ResponseBody = await handler({
                body: req.body,
                params: req.params,
                query: req.query
              });
              res.json(responseBody);
            } catch (err) {
              // do your standard error handling or whatever
              res.status(500).end("ow");
            }
          });
          return this;
        };
      }
    );
    return addables;
  }
}
const jsonRouter = new JsonRouter().route.get<{ request: number }, { response: number }>(
  "/hello-world",
  req => {
    return { response: req.body.request + 1 }; // type-checked result
  }
);
const app = express();

// custom middleware goes here

app.use('/', jsonRouter.router);

app.listen(8000)