什么是端到端类型?
相较于传统的开发流程 (后端写接口,前端将每个接口封装成请求函数), 端到端类型是让前端直接引用后端接口定义,从而减少重复编码,降低维护成本。
Tealina 通过一系列创新,实现无需切换服务端框架,也能拥有端到端类型和API文档,其核心是将后端定义的API转换成一个特定的类型,大概是这样:
go
// types/api-v1.d.ts
type ApiTypesRecord = { //一个两层结构的对象
post: { //第一层key是 http method
"category/create": { //第二层key是 URL
body: BodyType;
response: ResonseType;
//...parmas,header,query
};//第二层值是具体的数据类型
};
};
后端怎么做才能得到一个这样的数据结构?
约定文件结构,存放API的目录第一层是 http-method,第二层以下是每个具体API文件,用index.ts将当前层级目录下文件导出,代码如下:
javascript
//api-v1/index.ts
export default {
'post': import('./post/index.js'),//.js是新版Node的要求
//...
}
```
```ts
//api-v1/post/index.ts
export default {
'user/create': import('./user/create.js'),
//...
}
有了这样的文件结构, 后续只需要导入 `api-v1/index.ts` 文件,就可以拿到 api-v1 目录下所有API,顺便实现了批量导出,方便路由注册。 配合TS的 typeof 关键字,将对象转成类型。
typescript
// types/api-v1.d.ts
import apis from './src/api-v1/index.js'
type RawApiType = typeof apis
具体的body,response这些信息如何获取?
类型别名, 定义一个 HandlerType<Tinput, Toutput, Theader>
,然后约定所有API文件默认导出这个类型,就可以通过infer关键字拿到。
scala
//types/handler.ts
//简化版
type HandlerType<T extends RawPayload, Treponse, Theaders> = (req,res) => any
type ExtractApiType<T> = T extends HandlerType<
infer Payload,//用infer提取对应位置的类型
infer Response,
infer Headers
>
? Payload & { response: Response; headers: Headers } //组合成对象
: never
interface RawPayload {
body?: unknown
params?: unknown
query?: unknown
}
现在,你应该能看懂这张图:
有了API类型,前端可以基于它封装请求函数, 无需手动定义类型。 API文档也可以通过解析这个类型来生成, 有了约定的文件结构,自动化(生成api文件,更新index.ts)也就随之而来, 每个API通常会用到的类型基本是基于model定义的,那提供一个基于model生成类型的功能,很合理吧, 而这些,就是Tealina的功能。
为了更方便使用,Tealina提供脚手架工具 create-tealina: 用于创建开箱即用的脚手架项目:
perl
# pnpm
pnpm create tealina
# yarn
yarn create tealina
# npm
npm create tealina@latest
关联项目:
-
tealina: 命令行工具,用于生成类型,文档,用它创建和删除API文件会自动更新index.ts
-
@tealina/doc-ui: 作用类似swagger-ui, 拥有更加现代的界面和更强的功能
-
@tealian/doc-types: API文档类型,doc-ui就是根据它做的,你也可以借助它将API文档生成其他代码
高清视频演示
中文文档: cn.tealina.dev
GitHub:github.com/tealina/tea...