手摸手教你用 yapi-to-typescript生成Yapi的TypeScript資料型別

孤舟蓑翁發表於2021-10-19

一 背景

現代社會比較重視效率,本著這個思想宗旨,能用工具自動高效做的事情,就不要低質量的勤奮。yapi-to-typescript就是一款自動生成介面請求與響應的typescript資料型別定義的工具,可根據 YApi 或 Swagger 的介面定義生成 TypeScript 或 JavaScript 的介面型別及其請求函式程式碼。本文手把手教你在專案中把這個工具用起來,讓加班時間少一點,摸魚時間多一點。

二 安裝配置

2.1 在專案中安裝yapi-to-typescript工具包

yarn add -D yapi-to-typescript

2.2 配置工具

在專案根目錄下建立yyt.config.ts配置檔案

npx ytt init -c ytt.ts

每個配置項的含義參見官方配置文件,將初始配置檔案修改為:

import { defineConfig } from 'yapi-to-typescript';

/**
 * 生成Api介面名稱  Interface和ChangeCase資料型別參見node_modules\yapi-to-typescript\lib\esm\index.d.ts定義
 * @param interfaceInfo : Interface
 * @param changeCase:ChangeCase
 * @returns 請求響應介面名稱--pascal命名
 */
function genApiInterfaceName(interfaceInfo, changeCase) {
  // 取解析路徑dir最尾部的路徑作為字首路徑
  const lastPath = interfaceInfo.parsedPath.dir.split('/').pop();
  // 拼接字首路徑+檔名稱
  return `${changeCase.pascalCase(lastPath)}${changeCase.pascalCase(interfaceInfo.parsedPath.name)}`;
}

export default defineConfig([
  {
    serverUrl: 'http://yapi.xxx.com',
    typesOnly: true,
    target: 'typescript',
    reactHooks: {
      enabled: false,
    },
    prodEnvName: '專案名稱',
    // 將生成檔案路徑轉化成小駝峰命名方式
    outputFilePath: (interfaceInfo, changeCase) => {
      const filePathArr = interfaceInfo.path.split('/');
      const filePath = filePathArr.map((item) => changeCase.camelCase(item)).join('/');
      return `src/types/httpTypes/${filePath}.ts`;
    },
    // 生成ts檔案中請求引數interface名稱,將下劃線命名轉換成pascal命名
    getRequestDataTypeName: (interfaceInfo, changeCase) => {
      return `${genApiInterfaceName(interfaceInfo, changeCase)}Request`;
    },
    // 生成ts檔案中請求響應資料interface名稱,將下劃線命名轉換成pascal命名
    getResponseDataTypeName: (interfaceInfo, changeCase) => {
      return `${genApiInterfaceName(interfaceInfo, changeCase)}Response`;
    },
    // 響應資料中要生成ts資料型別的鍵名
    dataKey: 'retdata',
    projects: [
      {
        // token獲取方式: 在yapi-設定-token配置中檢視
        token: 'xxx-token',
        // 分類id查詢方式: 點選介面左側的分類選單,檢視url位址列最後面的數字獲取
        // 分類id配置特別重要,配置錯了無法生成對應的ts資料型別定義檔案
        categories: [
          {
            id: [139], // 批量加好友API分類id
          },
        ],
      },
    ],
  },
]);

 其中token和projects--categories--id的檢視方式分別是:

 在package.json中新增指令

  "scripts": {
    "ytt": "ytt",
  },

三 生成使用

3.1 生成api介面請求與響應的ts資料型別

yarn yyt

 注意:自動生成的ts資料型別檔案,是不需要新增到git倉庫中的,所以要在.gitignore中新增一條檔案版本管理忽略規則

# 自動生成型別不允許上傳
/src/types/httpTypes/*

3.2 引用方式

import type {AddClientToolsGetClientsRequest, AddClientToolsGetClientsResponse} from '@/types/httpTypes/addClientTools/getClients';

 3.2 列舉型別配置方法

 生成資料型別示例:

export type AddClientToolsGetClientsResponse = {
  ...,
  /**
   * 手機識別碼
   */
  phoneCode: string
  /**
   * 新增好友狀態標識 0-未新增 1-成功新增
   */
  state: 0 | 1
  /**
   * 複製次數
   */
  copyCount: number
}[]

四 踩坑分享

4.1 yyt.config.ts 中的projects--categories--id是個很關鍵的引數,如果配置錯誤,將無法生成ts資料型別定義檔案。配置成[0],是生成配置的token對應的api專案下所有介面的ts資料型別文件,配置成分組id,則生成的是配置的token對應的api專案下,某個分組的api介面請求與響應ts資料型別定義檔案。

    projects: [
      {
        categories: [
          {
            id: [139], // 分組id,  如果配置成[0]是生成全部
          },
        ],
      },
    ],

4.2 自動生成api介面請求響應ts資料型別定義文件之後,在業務檔案中引用時,卻報引用路徑有錯誤。解決方法: 以VSCode為例,按Ctrl+Shift+P,然後搜尋重啟TS伺服器,重啟TS服務,引用錯誤就會消失。

 4.3  yyt工具對yapi的編寫質量有一定的要求,如果後端編寫介面太隨意,會造成yyt指令執行報錯。比如如下的錯誤,yapi上api的介面地址帶有查詢引數,而ts的資料型別檔案路徑是根據api的介面地址生成的,檔案路徑中是不允許出現?的,一般需要後端修改api地址,如果後端不能及時修改,前端沒修改許可權又著急用,可以改配置檔案

    outputFilePath: (interfaceInfo) => {
      let filePathNames =  interfaceInfo.path;
      // ?在路徑中是非法的,所以需要擷取掉含有?的路徑後面的字元 類似這種:getFundManagerAwards?personalCode=101000231.ts
      filePathNames = filePathNames.slice(0, filePathNames.lastIndexOf('?'));
      return `src/types/httpTypes/${filePathNames}.ts`;
    },

4.4 yapi get請求的引數,無法指定引數型別,自動生成的引數型別都是string,不能滿足實際應用,需要對型別定義不符合使用場景的引數做如下處理:

import type {AddClientToolsGetClientsRequest, AddClientToolsGetClientsResponse} from '@/types/httpTypes/addClientTools/getClients';

type TTabVal = 1 | 2;

// 如果要對匯出的型別個別欄位型別進行修改,參照下方
type TReqParams = Omit<AddClientToolsGetClientsRequest, 'pageNum' | 'pageSize' | 'handleType'> & {
  pageNum: number;
  pageSize: number;
  handleType: TTabVal;
};

 

相關文章