最好用的 生成 TypeScript 类型和 API 请求代码的工具

orval 的目标是为你生成整个 API 调用层。你给它一个 OpenAPI 规范,它还你一整套可以直接在代码中导入和使用的 TypeSafe 的 API 函数。

各个库的优缺点 推荐使用 orval

@umijs/max-plugin-openapi openapi-ts-request orval
优点 配合umi配置简单 配置简单快速 适合大型项目,生成的类型很齐全,包括枚举都会生成
缺点 生成的类型简单(不会生成枚举或按文件生成) 生成的类型简单(不会生成枚举或按文件生成) 灵活性相对较低

orval 主要好处

  • 开箱即用,极高效率 适合大项目和新项目
  • 类型安全全覆盖
  • 强大的集成
  • 高度可配置
  • 现成配置 支持 angular-app react-app react-query vue-query next-app 等 真正的开箱即用。

安装

pnpm add orval --save-dev

配置文件 orval.config.js

module.exports = {
  api: {
    input: 'http://localhost/api-doc/openapi.json',
    output: {
      mode: 'split',
      target: './src/services/openapi.ts',
      schemas: './src/services/models',
      override: {
        mutator: {
          name: 'customClient',
          path: './src/services/request.ts',
        }
      },
      mock: false,
      prettier: true,
    },
  },
}

自定义请求函数

不使用 orval提供的请求函数,自定义请求函数 需要是RequestConfig类型

 interface RequestConfig {
   method: 'get' | 'put' | 'patch' | 'post' | 'delete';
   url: string;
   params?: any;
   data?: any;
   responseType?: string;
 }
  • override.mutator.name 自定义请求函数 导出的请求函数名称。
  • override.mutaror.path 自定义请求函数 的路径。

其中自定义请求函数。如果有params参数的, 用 queryString 或者自定义拼接请求参数。

 const queryString = params?`?${new URLSearchParams(
        Object.entries(params).reduce(
          (acc, [key, value]) => {
            if (value !== undefined) {
              acc[key] = String(value)
            }
            return acc
          },
          {} as Record<string, string>
        )
      ).toString()}`
    : ''

运行脚步

  • 自定义nodeJS 脚本 orval.ts
exec('npx orval --config orval.config.cjs', (error, stdout, stderr) => {
    if (error) {
        console.error('Exec error:', error);
    }
    if (stderr) {
        console.error('Stderr:', stderr);
    }
    if (stdout) {
        console.log('Stdout:', stdout);
    }
});
  • NPM 执行脚本
"script": {
    "orval" : "orval --config ./orval.config.js",
    "orval-ts": "ts-node ./orval.ts"
}

自定义openApi-plugin

因为 @umijs/max-plugin-openapi 这个插件自带的功能不支持生成枚举,在编码的时候想直接用枚举就不行。索性自定义以一个查看以实现以上功能。

在config 目录下面创建 plugins/openApi-plugin.ts 具体代码如下

import { IApi } from '@umijs/max';
import { generateService, GenerateServiceProps } from '@umijs/openapi';
import pkg from '../../package.json';

export default (api: IApi) => {
  api.describe({
    key: 'openAPI',
    config: {
      schema(joi) {
        return joi.alternatives().try(
          joi.object({
            schemaPath: joi.string().required(),
            projectName: joi.string(),
            namespace: joi.string(),
            requestLibPath: joi.string(),
            serversPath: joi.string(),
            mock: joi.boolean(),
            enumStyle: joi.string().valid('string-literal', 'enum'),
            splitDeclare: joi.boolean(),
          }),
          joi.array().items(
            joi.object({
              schemaPath: joi.string().required(),
              projectName: joi.string(),
              namespace: joi.string(),
              requestLibPath: joi.string(),
              serversPath: joi.string(),
              mock: joi.boolean(),
              enumStyle: joi.string().valid('string-literal', 'enum'),
              splitDeclare: joi.boolean(),
            }),
          ),
        );
      },
    },
  });
  api.registerCommand({
    name: 'openapi',
    description: pkg?.description,
    fn: async ({ args }) => {
      const config = api.config.openAPI || {};
      const configs = Array.isArray(config) ? config : [config];
      for (const cfg of configs) {
        api.logger.info(`[openApi] 正在生成: ${cfg.projectName || 'default'}`);
        await generateService({
          ...cfg,
          requestLibPath: cfg.requestLibPath || "import { request } from '@umijs/max'",
          serversPath: cfg.serversPath || './src/services',
          enumStyle: 'enum',
          declareType: 'interface',
        } as GenerateServiceProps);
        api.logger.info('[openApi] 生成完成');
      }
    },
  });
};

如何使用

在config.ts 里面 替换如下代码

  plugins: [path.resolve(__dirname, 'plugins/openApi-plugin.ts')],
  openAPI: [
    {
      schemaPath: `${SERVER_NAME_HOST}/api-doc/openapi.json/pc`,
      projectName: 'sign',
      namespace: 'sign',
    },
  ],
posted @ 2025-10-17 17:14  boygdm  阅读(46)  评论(0)    收藏  举报