接口类型怎么生成?JSON 转 TS 与 SQL 转实体类
对着接口返回手敲类型定义,是既慢又容易出错的事:字段少写一个、类型标错一次,编译期不会报,运行时才炸。这篇讲怎么从已有数据反向生成类型,以及生成后必须手工补哪几处。
- 手写类型定义的风险在于漏字段不会报错,只有运行到那一步才会出问题,而生成式做法能保证字段集合与真实数据一致
- JSON 只有 number 一种数字类型,无法区分 int 与 float,所以整数键生成 number 符合运行时实际
- 字段值为 null 时生成器只能推断为 null 或 any,这类字段必须手工改成可空联合类型,否则类型过窄
- 从 CREATE TABLE 生成实体类时,DDL 里的长度与精度不会被保留,字段是否可空则要看列定义有没有 NOT NULL
- 命名风格混用(接口用驼峰、数据库用下划线)是跨层开发里最多的低级 bug 来源,统一转换能一次改完
- JSON 转 XML 时数组会变成重复标签、属性用 @ 前缀表示,这两个约定在双向转换时都必须遵守才能往返一致
#手写类型定义的问题不在慢
手写类型定义的真正风险是漏字段不会报错 —— 少写一个属性编译器不会提醒你,只有代码跑到读取那个字段时才会暴露,此时往往已经上线。
从真实数据反向生成就没有这个盲区:字段集合直接来自样本,不可能漏。生成后你要做的只是修正推断不到位的类型,这比从零手写快得多,也更准。
| 你想做的事 | 用什么生成 | 输出 |
|---|---|---|
| 接口响应 → 前端类型 | JSON 转 TS 接口 | TypeScript 接口定义 |
| 建表语句 → 后端实体 | SQL 转实体类 | Java / C# / TypeScript |
| 结构 → 多语言模型 | JSON 转 Java Bean | 各语言实体类 |
| 命名风格不统一 | 变量命名转换 | 7 种风格互转 |
#从接口响应生成 TypeScript 类型
JSON 的数字类型在生成时会被统一推断为 number,这是正确的:JavaScript 运行时本来就不区分整数和浮点数。
用 JSON 转 TS 接口 的典型流程:
- 复制一份真实接口响应(要包含所有可能出现的字段,见下方提示)
- 粘进输入框,实时生成类型定义
- 选择嵌套对象是展开成独立接口还是内联
- 数组可选
T[]或Array<T>风格,按团队规范决定 - 设置根接口名,复制或下载
.ts文件
样本决定质量。如果拿到的响应里某个可选字段恰好没有值,生成器就无法知道它的存在 —— 而且 JSON 里字段值为 null 时,推断结果可能是 null 或 any,这两种都不是你想要的可选字段类型。生成后必须手工把这几个字段改成 string | null 这类联合类型。
类型推断的对应关系大致如下,了解之后就能预判哪些需要手工改:
| JSON 值 | 生成类型 | 需要手工修正的情况 |
|---|---|---|
"abc" | string | 若是日期字符串,可改为 string + 注释或 Date |
123 / 1.5 | number | 若是 ID 且超过 2^53,考虑用 string |
true | boolean | 一般无需修改 |
null | null 或 any | 几乎总需要改成可空联合类型 |
[...] 空数组 | any[] 或 never[] | 必须手工填入元素类型 |
{...} | 独立接口或内联对象 | 按嵌套深度决定是否展开 |
#从 CREATE TABLE 生成实体类
DDL 里包含的信息比 JSON 多,所以生成的实体类质量通常更高:字段是否可空、主键、字段注释都能直接映射。
用 SQL 转实体类 时把完整的建表语句贴进去,它会解析表名、字段名、类型与注释,支持三种输出:
- Java:字段带
@Id主键注解,类型按映射表转换 - C#:生成属性风格,含可空标记
- TypeScript:适合前后端同构项目
VARCHAR(255) 这类长度约束不会带到实体类里,因为实体类通常不关心存储长度;但 NOT NULL 会影响字段是否可空,这条一定要核对。另外数据库的 DATETIME 映射到 Java 时常见做法是 LocalDateTime,映射到 TypeScript 时则是 string,语言间的差异需要在生成后手工统一。
#命名风格不统一是隐性成本
接口用驼峰、数据库用下划线、常量用全大写 —— 这种跨层不一致是低级 bug 最常见来源,而且分散在很多文件里,很难一次找全。
用 变量命名转换 输入任意一种风格的名称,它会智能识别单词边界并给出 7 种风格的对应写法:
| 风格 | 示例 | 典型使用场景 |
|---|---|---|
| camelCase | userName | JavaScript / Java 变量与字段 |
| PascalCase | UserName | 类名、React 组件名 |
| snake_case | user_name | Python、数据库列名 |
| kebab-case | user-name | CSS 类名、URL 路径 |
| CONSTANT_CASE | USER_NAME | 常量、环境变量 |
| dot.case | user.name | 配置键、国际化 key |
| Title Case | User Name | 展示文本、标签 |
它的拆分逻辑能处理下划线、中划线、空格、驼峰边界和数字边界,所以 HTTPServerURL、user_name、user-name 都能拆对。
批量改名时先在 变量命名转换 里确认拆分结果是否正确,再去做全局替换。像 ID、URL 这类全大写缩写,不同工具的处理方式不一致,确认过再动手能省一次回滚。
#JSON 与 XML 互转的两个约定
数组转成重复标签、属性用 @ 前缀表示,这两个约定是 JSON 与 XML 往返转换能对上的前提。
用 JSON 转 XML 双向转换时:
{
"user": {
"@id": "1001",
"name": "张三",
"tags": ["前端", "后端"]
}
}对应生成的 XML 是:
<user id="1001">
<name>张三</name>
<tags>前端</tags>
<tags>后端</tags>
</user>理解这两点就够用了:@id 表示这是属性而不是子元素;tags 数组变成了两个同名标签。反向往回转时,同名标签会被还原成数组 —— 但如果原 XML 只有一个 <tags>,转回 JSON 时它会变成单个字符串而不是数组,这是 XML 本身的歧义,不是转换错误。
#什么时候该用哪个工具
| 你的输入 | 想要的输出 | 用哪个 |
|---|---|---|
| 接口返回的 JSON | TypeScript 类型 | JSON 转 TS 接口 |
| CREATE TABLE 语句 | Java / C# / TS 实体 | SQL 转实体类 |
| JSON 结构 | 多语言 Bean 类 | JSON 转 Java Bean |
| 一个变量名 | 7 种命名风格 | 变量命名转换 |
| JSON 数据 | XML 或反向 | JSON 转 XML |
| 格式混乱的 JSON | 可读的缩进格式 | JSON 格式化校验 |
生成前建议先确认样本本身是合法 JSON —— 否则生成器拿到的是一段解析失败的内容,报错信息容易让人误以为是生成器的问题。
#常见问题
#生成出来的类型可以直接用吗?
可以,但可空字段必须手工核对。这是唯一一个生成器无法准确推断的信息:JSON 里某个字段的值恰好是 null 时,推断结果可能是 null 或 any,两者都不是理想的可选字段类型。做法是把它改成 string | null 这样的联合类型,再打开 TypeScript 的严格空值检查验证一遍。
#为什么 JSON 转 TS 后整数也变成了 number?
因为 JavaScript 运行时只有一个数字类型 number,底层是双精度浮点,没有 int 与 float 之分。把 JSON 的整数生成成 number 是符合运行时实际的选择。要注意的是绝对值超过 2^53 的整数在这个类型下会丢精度,这类字段(如雪花算法 ID)建议在接口层就序列化成字符串。
#空数组生成的类型为什么是 any[]?
因为空数组没有任何元素可供推断。这是信息缺失,不是工具缺陷 —— 你可以在样本里放一条有真实元素的记录再生成,或者手工把 any[] 改成具体类型。类型安全的项目里建议让样本尽量贴近真实数据,而不是用精简过的示例。
#数据库字段类型会完整映射到实体类吗?
长度与精度这类存储层约束不会带过去,例如 VARCHAR(255) 只会变成 string 或 String。是否可空会映射(取决于 NOT NULL),主键也会识别并加注解。日期时间类型在各语言间差异较大,生成后需要按项目规范统一,比如 Java 常用 LocalDateTime 而 TypeScript 用 string。
#命名转换能处理全大写的缩写词吗?
能拆开,但不同工具的约定不完全一致。像 HTTPServerURL 这类名称,有的工具拆成 http、server、url 三个词,有的会保留 HTTP 原样。批量改名之前先在小样本上确认拆分结果,避免全局替换后才发现风格不符合预期。