JSON → TypeScript 转换器,免费
粘贴 JSON,立即获得 TypeScript 接口。
使用方法
- 将您的 JSON(对象或数组)粘贴到左侧面板。
- 点击转换· TypeScript 接口会出现在右侧。
- 根据需要调整根名称并启用选项。
- 点击复制输出以复制生成的代码。
常见问题
支持嵌套对象吗?
支持。每个嵌套对象都会获得自己的命名接口。数组元素也会被分析以确定元素类型。
混合类型的数组会怎样处理?
如果数组包含不同类型的元素,转换器会使用联合类型(例如 string | number)。
支持根节点为 JSON 数组吗?
支持。如果根值是数组,转换器会分析其元素并生成合适的接口,以及数组的类型别名。
转换器的实际工作原理
它解析您的JSON,遍历每个值,并生成一组描述该形状的TypeScript interface 声明。嵌套对象各自获得一个命名接口,名称从父属性键以PascalCase派生(user 字段变为 User 接口)。当两个嵌套对象在名称上冲突时,第二个获得数字后缀(User、User2)。在根级别,数组变为 type Root = RootItem[]; 别名加上 RootItem 接口;对象变为单一 Root 接口(或您在「根名称」字段中填写的名称)。
示例输入与输出:
// Input
{
"id": 42,
"name": "Ada",
"active": true,
"tags": ["admin", "billing"],
"profile": { "bio": "Programmer", "link": null }
}
// Output
export interface Root {
id: number;
name: string;
active: boolean;
tags: string[];
profile: Profile;
}
export interface Profile {
bio: string;
link: unknown;
}
JSON → TypeScript 类型映射
| JSON值 | 生成的TS类型 |
|---|---|
"hello" | string |
42 或 3.14 | number(TS没有单独的整数类型) |
true / false | boolean |
null | unknown(转换器无法判断该字段在此样本中是可空还是缺失) |
[] | unknown[] |
[1, 2, 3] | number[] |
[1, "x"] | (number | string)[] |
{ "a": 1 } | 命名的 interface |
对于根级别的对象数组,转换器将所有条目的键合并为一个代表性接口。当条目形状相同时这是合理的近似,但当形状确实存在差异时(例如异构事件数组)会丢失信息。对于这种情况,需要在生成后手动编写判别联合类型。
为什么对象用 interface,根数组用 type
TypeScript官方手册给出了一个简明启发原则:「如果需要启发式规则,请使用 interface,直到需要使用 type 的功能为止。」两者均为结构化类型,均可描述对象形状,但对于对象形状,interface 更优,因为它支持声明合并(重新打开接口添加字段)、与 extends 配合清晰,并在编译器错误中以名称形式显示。当需要原始类型的联合、多类型的交叉或为非对象内容命名时,type 别名是必要的,这就是为什么根级别数组使用 type Root = RootItem[]; 别名而非接口。
命名说明:转换器使用PascalCase,不带遗留的 I 前缀(使用 User 而非 IUser)。现代TS风格指南(Google、微软、React社区)几乎普遍去掉了该前缀。属性名与JSON键完全匹配(JSON使用camelCase则用camelCase,使用snake_case则用snake_case)。不是有效JS标识符的键(含连字符、空格或以数字开头的键)会被加引号:"foo-bar": string;。
本工具的局限性(坦率说明)
单个JSON示例携带的信息比真实schema少,因此仅从输入无法检测到一些理想情况下应能检测到的内容:
- 可选字段。示例中的每个属性都变为必填项。如果真实API有时会省略某个字段,需要手动添加
?:email?: string;。或在多个示例上运行转换器并对结果取联合。 - 可空检测。示例中的
null变为unknown;转换器无法判断该字段是真正可空的(string | null)还是在此样本中恰好为null。需根据API合同手动调整。 - 字符串字面量联合。值为
"active"的状态字段变为string,而非"active" | "inactive" | "pending"。转换器看不到其他可能的值。 - 日期类型检测。像
"2024-04-12T10:00:00Z"这样的ISO 8601字符串保持为string。JavaScript的Date不是JSON类型。 - 判别联合。如果根数组包含不同形状的条目(不同类型的事件、多态记录),转换器会将所有键合并为一个接口,而不是生成带标记的联合类型。对于真正的异构数据,需要手动编写联合类型。
- 数字精度。JavaScript的
number能安全表示253−1以内的整数。当通过JSON.parse解析时,较大的整数ID会丢失精度;如果您的API返回64位整数,最安全的模式是将其作为字符串发送并类型化为string。
适用场景
- 从真实API响应中引导类型。调用接口,粘贴JSON,获得一组起始接口定义。然后针对可选字段和字符串字面量进行手动调整。
- 为无类型的第三方SDK添加类型。许多旧版JS库不附带类型定义。从示例响应生成比阅读文档更快。
- 在前端和后端之间共享类型。从一个规范示例生成,然后复制到两个代码库中(或通过发布的类型包共享)。
- 将JS代码库迁移到TypeScript。从应用中流经的真实数据生成类型,逐步为函数签名添加注解。
- 为配置文件生成类型。严格类型使配置错误在编译时可见。
- 记录内部数据文件的形状。生成的接口同时作为机器可读的文档。
代码优先 vs 模式优先 vs 直接推断(本工具的定位)
从运行时数据获取TypeScript类型的三种常见工作流:
- 代码优先运行时验证器:Zod、Yup、Effect Schema、Joi。以JS编写验证器模式,通过推断同时获得运行时解析和TypeScript类型。模式即真值来源。当验证与类型同等重要时为最佳选择。
- 模式优先:编写JSON Schema或OpenAPI规范,通过
quicktype、json-schema-to-typescript或openapi-typescript等工具生成TypeScript类型。当API合同跨越多种语言时为最佳选择。 - 直接样本推断(本工具,以及quicktype的纯JSON模式),粘贴真实数据,获得类型。速度最快;验证保障最弱,因为没有机制在运行时对照类型检查数据。
正确的选择取决于您的关注点主要是静态类型检查(本工具很适合)还是同时需要运行时安全(请使用Zod / Effect Schema)。
常见错误
- 将生成的类型视为完成的规范。它们只是70%完成的起点。为可选字段添加
?,在真正可空的地方添加| null,在适用的地方添加字符串字面量联合。 - 从单个示例生成,而API存在变体。一个有时包含
email有时不包含的用户对象,将生成结果中该字段被视为「必填项」。请在多个示例上运行并对结果取联合,或手动编辑。 - 自动将所有内容标记为
readonly。对不可变数据流有用,但对您要修改的状态对象不适用。请谨慎使用readonly开关。 - 相信大整数ID的精度。JavaScript的
number上限为253−1。对于64位ID,请以字符串传输并类型化为string。 - 混淆
interface和type。不同的工具,各有权衡。TypeScript手册的启发原则是「除非需要只有type才具备的功能,否则使用interface」,这正是本工具所遵循的。 - 将机密JSON粘贴到服务器端转换器。真实的API响应通常包含客户数据、凭证、内部ID。仅在浏览器中转换(本工具)可确保数据留在您的设备上。
常见问题解答
为什么我的所有字段都被标记为必填?
因为单个JSON示例无法告诉转换器哪些字段在真实API中有时会缺失。示例中出现的每个键都变为必填项。如果您知道某个字段是可选的,请手动添加尾部 ?:email?: string;。要进行多示例的可选性检测,更高级的 quicktype CLI原生支持此功能。
为什么我的null字段被类型化为 unknown?
因为转换器无法从单个null中判断该字段是否始终可空(string | null),还是在此样本中恰好为null(string)。unknown 是保守的默认值;TypeScript会强制您在使用值之前缩小类型,这比 any 更安全。了解API意图后,手动编辑为 string | null。
我应该使用 interface 还是 type?
TypeScript官方手册的启发原则:使用 interface,直到需要只有 type 才提供的功能,主要是联合类型、交叉类型或为原始类型命名。本转换器遵循该规则:每个对象形状使用 interface,根数组别名使用 type。部分风格指南建议默认使用 type(Matt Pocock曾公开论证过),但传统默认是对象使用interface。
我的JSON会被上传到任何地方吗?
不会。转换是一个自包含的JavaScript IIFE,通过 JSON.parse 解析您的JSON,遍历值,并将TypeScript输出写入文本区域。没有fetch请求,没有携带JSON内容的分析调用,没有服务器。这很重要,因为真实的API响应通常包含客户数据、内部ID或凭证,您不希望这些流经第三方。
关于JSDoc、Zod或运行时验证呢?
本工具仅生成编译时TypeScript类型:无运行时验证器(无Zod / Yup / Effect Schema),无JSDoc注释。如果需要兼具静态类型的运行时验证,请在Zod中编写模式并使用Zod的 z.infer<typeof Schema> 来派生类型。如果您有JSON Schema并希望同时进行运行时验证和TS类型生成,json-schema-to-typescript + AJV是常用的组合。
为什么接口名称没有 I 前缀?
因为大多数现代TypeScript风格指南都去掉了它。Google的TypeScript风格指南明确建议反对使用;React社区已统一使用无前缀的PascalCase。遗留的 IUser 约定来自早期TypeScript中C#/Java的影响;当前实践是直接使用 User。