apifox和ts类型导出的最佳实践

相信很多小伙伴现在都已经进入了vue3 + ts的大时代。这样就会面临着ts类型维护的问题。本篇文章就提供给你一个可能的解决方案。

在我们编写ts类型的时候 ,有绝大部分其实都是基于对接口的入参和返回值类型的一个拓展。所以本篇文章就是教你如何快速的拿到接口相关的ts类型。

当然有个很重要的前提 后台要有接口文档。要是公司这东西都没有 也别上ts了 没必要。

apifox

我们的接口文档都是用apifox记录的,所以我也就基于apifox来讲述我的解决方案。

apifox的具体使用方式我这里就不做赘述了,不明白的可以移步Apifox 快速入门 | Apifox 帮助文档

当然你有什么用不明白的地方 也欢迎评论区交流。

在你启动apifox的客户端以后,apifox会在你本地启动一个,这样的服务http://127.0.0.1:4523/。我们通过这个服务访问这样的一个地址

bash 复制代码
http://localhost:4523/export/openapi?projectId=${你的项目id}&specialPurpose=openapi-generator

然后你就可以通过该 URL 自行使用 OpenAPI 规范 (中文版) (apifox.cn) 生成代码,以实现更个性化的需求。

ps:

这个地址你可以在这里看到

项目id在这里看到

OpenApi的数据格式转换

下面言归正传。我们先看一下这个url带给了我们什么样的数据。

我们把路径放入浏览器中就可以直接看到这样一个数据,可以大致的看出来他是对我们接口信息的一个json结构描述。下一步我们就要思考怎么样把这些数据转化为ts类型呢?

这一步就需要我们引入一个挺有名的依赖包 openapi-typescript。使用方式也很简单

javascript 复制代码
const fs = require(`fs`)
const axios = require(`axios`)
const path = require(`path`)
const openapiTS = import(`openapi-typescript`)
​
 const axiosData = axios
    .get(`http://localhost:4523/export/openapi?projectId=${projectId}&specialPurpose=openapi-generator`)
    .then(async response => {
      const { default: transform } = await openapiTS
      const typeDefinitions = await transform(response.data)
      const filePath = path.join(__dirname, `/src/types/apiFox/`, filename)
      fs.mkdirSync(path.dirname(filePath), { recursive: true })
      fs.writeFile(filePath, `/* eslint-disable */\n${typeDefinitions}`, err => {
        if (err) throw err
        console.log(`The file ${filename} has been saved!`)
      })
    })
    .catch(error => {
      console.error(error)
    })

这是段node代码。这段代码执行后 我们就会得到一个内容大概是这样的文件。

css 复制代码
/* eslint-disable */
export interface paths {
  '/literatureSearchHistory/add': {
    post: {
      requestBody?: {
        content: {
          'application/json': {
            query: string
          }
        }
      }
      responses: {
        200: {
          content: {
            'application/json': {
              data: {
                id: string
              }
              code: string
              message: string
            }
          }
        }
      }
    }
  }
}

我们可以在requestBody和responses看到很明显是有了ts类型了。下面我们只需要拿到这些类型就可以正常使用了。例如:

css 复制代码
type Response =  paths[`/selectAll`][`post`][`responses`][200][`content`][`application/json`][`data`]

虽然拿到了类型 但是这长的离谱。太不优雅了 让我们把他封装一下。

简化ts类型

scala 复制代码
import type { paths, components } from './main'
​
type Defined<T> = Exclude<T, undefined>
type ExtractType<Method extends keyof any, Path extends keyof Paths, Paths extends Record<string, any>> = {
  params: Paths[Path] extends { [K in Method]: any }
    ? Defined<Paths[Path][Method][`requestBody`]>[`content`][`application/json`]
    : unknown
  response: Paths[Path] extends { [K in Method]: any }
    ? Paths[Path][Method][`responses`][200][`content`][`application/json`][`data`]
    : unknown
}
​
//paths 与 components 是两个动态值。我们有新项目复制一下代码 修改动态值即可
export type PostType<Path extends keyof paths> = ExtractType<`post`, Path, paths>
export type GetType<Path extends keyof paths> = ExtractType<`get`, Path, paths>
export type DataModel<DataModelName extends keyof components[`schemas`]> = components[`schemas`][DataModelName]

使用的时候这样即可,是不是简单了很多呢。

go 复制代码
type Params = PostType<`接口路径`>[`params`]     //获取接口传参类型
type Response = PostType<`接口路径`>[`response`] //获取接口返回值类型
type Model = DataModel<`模型名称`>               //获取数据模型类型

结合我们api层的接口文件大概就是这样的

typescript 复制代码
const url = {
    getSystems: `/dsClass/querySystem` as const, //这个as const 必不可少
}
​
type Params = PostType<typeof url.getSystems>[`params`]    
type Response = PostType<typeof url.getSystems>[`response`]
function getSystems(params?:Params): Promise<Response> {
    return etlPost(url.getSystems, params)
  }
}
​
export {getSystems}

简单的应用到这里就完成了!

相关推荐
DoraBigHead5 分钟前
React 中的代数效应:从概念到 Fiber 架构的落地
前端·javascript·react.js
LuckySusu5 分钟前
【vue篇】Vue 性能优化全景图:从编码到部署的优化策略
前端·vue.js
卓伊凡10 分钟前
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓
前端
笨笨鸟慢慢飞12 分钟前
Vue3后退不刷新,前进刷新
前端
LuckySusu15 分钟前
【vue篇】SSR 深度解析:服务端渲染的“利”与“弊”
前端·vue.js
LuckySusu15 分钟前
【vue篇】SPA 单页面应用:现代 Web 的革命与挑战
前端·vue.js
LuckySusu16 分钟前
【vue篇】Vue 初始化页面闪动(FOUC)问题终极解决方案
前端·vue.js
fruge18 分钟前
从 0 到 1 理解前端工程化:图表化解析核心逻辑
前端
LuckySusu18 分钟前
【vue篇】技术分析:Template 与 JSX 的本质区别与选型指南
前端·vue.js
BestStarLi23 分钟前
个人写码感悟:TailwindCSS不要忽视子选择器
前端