不知道大家有没有跟我一样的情况,就是 Typescript 用了那么久,总是不得其法。
- 想写好,就需要耗费大量的时间精力,跟着后端 api 文档一个个对着写。
- 想偷懒,写几个any,代码出了bug,又不好处理。
而且不只普通通开发者有这种苦恼,就连大神也无法避免。之前就有报道大神放弃了在项目中使用 Typescript。
但是用 AI 编码之后,为了避免 AI 出现低级错误,我还是毅然选择了 Typescipt。调试中能看到 AI 写的错误,而且最新的大模型还能根据这些报错自行修正。用起来的确方便了不少。
既然 Typescript 还是必须,那何不让 AI 给出最佳实践,帮我们突破一下之前使用 Typescript 的局限?
说干就干,三两句话,AI 就列出了目前可用的几种方案。
一、方案总览
目前来说,有四种方案。AI 贴心地给出了不同项目场景下的方案选择方法。
场景 | 推荐方案 |
---|---|
传统 REST API | OpenAPI + 自动生成 |
GraphQL 架构 | GraphQL Codegen |
灵活接口/无文档 | Zod 运行时校验 |
全栈 TypeScript | tRPC(替代方案) |
全栈的 tPRC 方案,可以去官网围观。Node.js tRPC官网
下面是 AI 给出的 1-3 种方案的具体代码。
二、具体实践方案
方案 1:使用 OpenAPI 规范(推荐)
适用场景:RESTful API,后端支持 Swagger/OpenAPI 规范
bash
# 安装代码生成工具
npm install openapi-typescript @openapitools/openapi-generator-cli -D
-
生成 TypeScript 类型:
bashnpx openapi-typescript http://后端地址/swagger.json -o src/api/types.d.ts
-
生成 API Client:
bashnpx @openapitools/openapi-generator-cli generate \ -i http://后端地址/swagger.json \ -g typescript-axios \ -o src/api/client
-
前端调用示例:
typescriptimport { UserApi, UserDto } from './api/client'; const userApi = new UserApi(); // 完全类型安全的调用 const getUser = async (id: number): Promise<UserDto> => { const res = await userApi.getUserById(id); return res.data; // 自动推断为 UserDto 类型 };
这个方案比较好理解,就是使用工具,读取 swagger.json,直接输出一份 type 文件,还有请求的函数集。
优点很明显,全自动化同步,后端修改能自动更新前端类型。
而缺点就是有个前提,后端必须按规范好好地写代码,才能输出正确的 swagger。另外这个方案会输出封装好的 axios,理解有一点费劲,修改有一定的麻烦。
方案 2:GraphQL + Codegen
适用场景:使用 GraphQL 的现代架构
bash
# 安装依赖
npm install @apollo/client graphql
npm install @graphql-codegen/cli -D
-
配置 codegen.yml:
yamlschema: http://后端地址/graphql documents: src/**/*.graphql generates: src/generated/graphql.ts: plugins: - typescript - typescript-operations - typescript-react-apollo
-
定义查询:
graphql# src/users/user.query.graphql query GetUser($id: ID!) { user(id: $id) { id name email } }
-
生成类型:
bashnpx graphql-codegen
-
前端调用:
typescriptimport { useGetUserQuery } from './generated/graphql'; function UserProfile({ id }: { id: string }) { const { data } = useGetUserQuery({ variables: { id } }); // data.user 自动具备完整类型提示 }
同样的,基于 GraphQL 框架,也有代码生成器,只需要配置好相关文档,也能输出 type 文件来。
GraphQL 框架,一定程度上减少了增删改查接口开发的工作量,把数据库、前后端工作串联起来了。所以这个方案是优于方案 1,但她仅针对于使用了 GraphQL 框架的项目。
方案 3:手动定义 + Zod 运行时校验
适用场景:GraphQL、未提供 OpenAPI 的 REST API
bash
# 安装校验库
npm install zod
-
定义共享类型:
typescript// src/api/schemas.ts import { z } from 'zod'; // 1. 定义后端接口响应基础结构 export const ApiResponseSchema = z.object({ code: z.number(), data: z.any().optional(), message: z.string().optional(), }); // 2. 定义具体业务 DTO export const UserSchema = z.object({ id: z.number(), name: z.string(), email: z.string().email(), }); export type User = z.infer<typeof UserSchema>;
-
封装 API 请求器:
typescript// src/api/client.ts import axios, { AxiosResponse } from 'axios'; import { ApiResponseSchema, UserSchema } from './schemas'; // 增强版 axios 实例 const apiClient = axios.create({ baseURL: '/api', timeout: 10000, }); // 响应数据校验拦截器 apiClient.interceptors.response.use((response) => { const validated = ApiResponseSchema.parse(response.data); // 具体业务数据校验 if (validated.data) { // 根据接口路径动态校验(实际项目需完善路由匹配逻辑) if (response.config.url?.includes('/users/')) { validated.data = UserSchema.parse(validated.data); } } return { ...response, data: validated }; });
-
前端调用:
typescript// 获取用户 const fetchUser = async (id: number): Promise<User> => { const res = await apiClient.get(`/users/${id}`); return res.data.data; // 自动推断为 User 类型 };
这个方法应该是适合大部分项目的方案了,它的优点是,运行时校验兜底,防止类型欺骗。
Zod 库有一个好处就是省去了不少写验证方法的时间。
但是缺点就再明显不过了,前端还是要写大量的代码来实现。
总结
理论上来看,无论是传统 REST API,还是新的 GraphQL 架构其实都有工具自动生成 type 文件,前端基本上调用生成的即可。
但是实践起来往往就不是那么一回事了。
- 传统 REST API 中,估计很多项目都是老旧项目了。swagger支持一般。如果要重新写 swagger,无疑是增加了后端的工作量。
- GraphQL 架构,目前我经历过的,见过的几乎没有任何一家国内公司用的。
- 对于方案四的 tRPC,需要前后端都用 Node 实现,现在国内也很少有这样的公司。
综上来看,执行起来还是困难重重。
唯独前端仔手动方案写类型的方案,才是最实际的。如果你还有能力改,可以尝试用 Zod 减少一点工作量吧。
启发
这件事也给我一些启发:
- 一件事总需要一个人干,如果不是你干就是别人干,别人不干就是你干,工作量不会凭空消失。
- 标准化的流程越早执行越好。排除一切困难执行,最后带来的收益一定是值得的。
第二点也是我一直想的一个事情,对标准化的严格执行,其实就是我们缺失的。
我们前端还在争论要不要配置 eslint,后端还在争论要不要执行 Restful API 的时候,别人可能已经把整个流程融合起来,开发了配套的生态内容。而不去争论,直接用一套标准解决方案来做的时候,往往才是最省时省力的。
于是,在国外转向 AI 的时候,由于一切都是标准化的,整个运转起来也飞快。而我们,虽然也在发展,但总感觉一直在追随它人的脚步。
这种情况,甚至还延伸到企业信息化,总有企业说有自己的流程,于是搞出了很多奇奇怪怪的项目、子项目。在企业发展过程中,越来越繁杂,越来越冗余,最后变革起来就越来难。
对此,你有什么看法?
欢迎在评论区留下你的足印。