json数据转化成interface属性
核心矛盾:接口返回几十上百个字段,不想一个个手写 interface 属性 ,同时又要规避
any这条 eslint 规则
方案 A:基础接口 + 索引签名(推荐,平衡类型安全和开发效率)
固定已知字段,剩下未知字段交给索引签名 [key:string]: unknown,不用把所有后端字段全部写一遍。
interface LoginApiRes {
code?: number
msg?: string
data?: {
access_token: string
// 已知字段写在这里
[key: string]: unknown
}
[key: string]: unknown
}
特点:
access_token这类你代码里会用到的字段,保留强类型提示;- 后端额外返回的一堆杂字段,全部归入
[key:string]: unknown,不用手动定义; - 没有
any,ESLint 不会报警告; - 缺点:访问未知字段时 TS 会要求做类型判断,不能直接拿来用。
示例:
const loginRes: LoginApiRes = await netHelper.postLoginData(...)
// 已知字段:有智能提示 ✅
loginRes.data?.access_token
// 未知额外字段:可以读取,但TS要求类型收窄
const extra = loginRes.data?.otherField
if(typeof extra === 'string'){
// 这里 extra 才被识别为 string
}
方案 B:泛型封装请求工具(终极方案,大型项目首选)
改造 netHelper 的请求方法,支持传入泛型指定返回类型,不用每次手动写接口。
// netHelper.ts
// 基础通用后端返回结构
interface BaseApiRes {
code: number
msg?: string
[key: string]: unknown
}
// 泛型,T 代表data里面的业务类型
export function postLoginData<T extends object>(url:string, data: unknown):Promise<BaseApiRes & {data?: T}> {
// 原有axios请求逻辑...
}
使用时:只需要定义data 内部用到的少量字段
// 只写你业务代码要用到的字段,其余后端返回字段自动兼容
interface LoginData {
access_token: string
}
const loginRes = await netHelper.postLoginData<LoginData>(urlConfig.login.loginUrl, form)
loginRes.data?.access_token // 类型提示
优势:一次封装,全局所有接口复用。每个接口只需要定义自己用到的字段,多余字段由基础索引签名接管,不用写全部字段。
方案 C:自动生成接口类型(后端字段巨多,适合后端提供 OpenAPI)
如果后端有 Swagger / OpenAPI 文档,用工具自动批量生成 TS 接口 ,不用手动抄写。
常用工具:
-
openapi-typescript:从 openapi.json 一键输出全部.d.ts类型文件pnpm add openapi-typescript -D
npx openapi-typescript http://后端地址/v3/api-docs --output src/types/api.ts -
优点:一次性生成全部接口、所有字段,类型完整;
-
缺点:后端接口改动时,需要重新执行命令更新类型。
怎么选?
- 普通后台项目(几十个接口,字段不算爆炸)👉 方案 A,简单,改动小,不用改 netHelper
- 大型项目、大量接口,长期维护 👉 方案 B(泛型封装 netHelper)
- 后端提供 swagger,字段上百个 👉 方案 C,自动生成类型