我看之前楼层都在情绪输出,我来说说我的思考吧。
两个前提:
1. 老板只在意业务功能是否实现,没人在意前后端之间的接口质量;
2. 督促后端交付高质量接口的沟通成本远大于前端写几行 map 的开发成本;
故结论,前端兼容。
问题是,对于前端的某一字段,不同的后端提交、响应不同,甚至值的类型也不同。
导致在写 TypeScript 时,就要定义大量 TS 类型,还很难起名。
但仔细想想我们真的需要这些“一次性”类型吗?
看个例子,假设我们有两个接口:
```JavaScript
// id 查 user
const res = fetch.get('/user', { id: 1 })
console.log(res.body) // { id: 1, name: 'alice' }
// id 改 user 名
const res =
fetch.post('/user', { user_id: '1', new_username: '' })
console.log(res.body) // { code: 1 }
```
很难受吧,查和改的字段居然不一致。
那我用户 ID 究竟叫 id 还是 user_id ?类型究竟是 number 还是 string ?
很简单,按前端方便来:
```
type User = {
userId: string,
username: string
}
<div>
<div>用户 ID:{{userId}}</div>
<div>用户名:<input type="text" value="{{username}}" /></div>
</div>
```
???
因为 JavaScript 里常用驼峰命名,userId 通常也只是展示,不会涉及什么数值运算,绑定 input 之类也比较方便…
噢,哈哈,你肯定早就知道这些,我知道你是在疑惑,接口怎么办?
别急。
我们知道,TypeScript 类型系统很好很强,除非 any 泛滥。
要想抑制 any 渗入 TS ,就要观察 any 从哪产生:
什么函数返回 any ?
- JSON.parse()
- fetch()
- ...
喔,外部数据流入 TS 时,就是 any ,有才有德的我知道,此时我应该立刻手动为标记类型:
```JavaScript
// 接口响应类型
type GetUser = { id: number, name: string }
// 前端易用类型
type User = { userId: string, username: string }
function fetchUser(userId: string) {
// 外部数据
const res = fetch.get('/user', { id: Number(userId) })
console.log(res.body) // { id: 1, name: 'alice' }
// 标记类型 any -> GetUser
const data: GetUser = res.body
// 转为前端易用的格式
const user: User = {
userId: String(
data.id ?? ''),
username:
data.name }
return user
}
```
很好很完美,我们成功封装了一个接口请求函数,它能通过 string 的 userId ,查到 User 数据,以前端想要的格式。
但多看一眼,我们真的有必要定义 GetUser 吗?
简化下可以吗:
```JavaScript
type User = { userId: string, username: string }
function fetchUser(userId: string): User {
const res = fetch.get('/user', { id: Number(userId) })
return {
userId: String(
res.body.id ?? ''),
username:
res.body.name }
}
```
噢,虽然 res.body 是 any ,虽然按照 TypeScript 最佳实践我应该马上声明它的类型,但事实上,完全可以将这个明晰 any 的过程延迟到数据转换一并进行。
这样一切就变得简单多了,只要我守好数据流入和流出的关口,那无论多离谱的后端,我都不需撕逼,分钟对接:
```JavaScript
function updateUser(userId: string, username: string): boolean {
const res =
fetch.post('/user', {
user_id: Number(userId),
new_username: username
})
return res.code === 1
}
```
于是作为前端:
在开发阶段,我以最舒适的姿势定义 State 的数据结构、绑定 UI 组件。
在联调阶段,我直接对着浏览器抓包的响应体,实现关口函数内的转换。
完全摆脱各接口字段定义不一致、实际响应和接口文档不符、string 和 number 类型没对上之类来回沟通筋疲力尽的鸡零狗碎。
再温故一遍:
1. 老板只在意业务功能是否实现,没人在意前后端之间的接口质量;
2. 督促后端交付高质量接口的沟通成本远大于前端写几行 map 的开发成本;