TypeScript interface / type 转 Zod schema, 支持 union / 可选 / 嵌套 / 泛型 / enum / Record / Map / Set, 一键拷贝即用。
- 本地处理
- 分类 开发运维
- 适合 格式化、校验、压缩或检查和代码相关的文本。
TS → Zod 映射规则
常见写法一一对应: string → z.string(), { a: T } → z.object({ a: T }), T[] → z.array(T), 'a' | 'b' → z.enum(['a', 'b']), T | null → T.nullable(), Partial<T> → T.partial(), Record<K, V> → z.record(z.string(), V)。Zod 表达不了所有 TS 形态 —— 条件类型、mapped type、template literal type、extends 里的 infer —— 这几类会落成 z.unknown(), 并在输出顶上列出 warning 提醒你手改。
这个工具能做什么
把 TypeScript 的 `interface` 或 `type` 粘进来, 拿到一段可以直接 塞进运行时校验层的 Zod schema。日常项目里会用到的写法全都覆盖: 可选 `?` 和 `readonly`, 字符串字面量 union 自动折叠成 `z.enum`, `T | null` 简写成 `.nullable()`, 嵌套对象字面量 (内联或抽成 const), 数组 / 元组 / `Record<K, V>` / `Map` / `Set`, `Partial` / `Required` / `Pick` / `Omit`, interface `extends` 自动用 `z.intersection` 拼起来。解析器约 400 行手写 递归下降, 不引 `ts-morph`, 不引 TypeScript 编译器 shim, 不发 请求。全部在你的浏览器标签页里跑, TS 源码不出页面。 Zod 表达不了的语法 (条件类型、mapped type、template literal type) 会在输出顶上以 warning 列出, 告诉你哪几条要手改, 不会 默默吞掉。
工具细节
- 输入
- 文本 + 数值 + 结构化内容
- 页面会根据工具类型展示文本框、数值控件、文件选择或结构化输入。
- 输出
- 即时结果 + 复制 + 下载
- 结果区优先给出可操作结果,支持项会显示复制、下载或可视化预览。
- 隐私
- 浏览器本地处理
- 主工具逻辑未发现外部 API 调用,输入通常留在当前标签页内处理。
- 保存 / 分享
- 可分享链接状态
- 关键设置会进入 URL,复制链接后别人能复现同一组参数。
- 性能预算
- 首屏 JS ≤ 28 KB
- 没有声明 WASM 依赖,适合快速打开和移动端使用。
- 适用场景
- 开发运维 · 程序员
- 分类和职业标签用于推荐相关工具、组织内链,并帮助用户快速判断是否适合当前任务。
怎么用
-
1. 输入
把内容粘贴或拖入工具面板。
-
2. 处理
点击按钮,在浏览器内本地处理,文件不上传。
-
3. 复制 / 下载
一键复制结果或下载到本地。
TypeScript 转 Zod Schema 适合怎么用
适合穿插在写代码、查问题、做 Review、上线前的小任务里。
适合开发场景
- 格式化、校验、压缩或检查和代码相关的文本。
- 把片段整理好再放进文档、工单、提交或交接材料。
- 不切换工具,快速检查一个小 payload。
开发检查项
- 压缩、混淆这类不可逆处理,先对副本操作。
- 除非确认工具本地处理,不要粘贴密钥和敏感片段。
- 转换后的代码上线前,仍要跑自己的测试或 lint。
下一步可以接着做
这些入口会把当前任务接到更完整的工具链里。
真实使用场景
给已经类型化的 fetch() 边界加运行时校验
你已经有 `interface ApiResponse { ... }`, 代码里 `const data = await res.json() as ApiResponse` 这一行, TS 相信你, 服务端不一定。把 interface 粘进来, 拷生成的 `ApiResponseSchema`, 把那个 cast 换成 `ApiResponseSchema.parse(await res.json())`。服务端返回了 意外形状, 在边界上就抛清楚的 ZodError, 不会再让你在三层 call-stack 之外看 "undefined is not a function"。
把 JSON → TS 推出来的类型再推一道 Zod
昨天用 /json-to-typescript-interface 从 Stripe webhook 样本推了一组类型。把推出来的 TS 粘到这里, 拿到对应的 Zod schema。现在静态类型和运行时校验都来自同一个 JSON payload, 一致是因为同源, Stripe 加字段后两边都重新生成, 不会漂走。
给 feature flag 配置文件在加载时上锁
你发了一个 `flags.json` 配置, 想让 `loadFlags()` 在同事 填错时大声响。先写类型: `interface Flag { key: string; enabled: boolean; rollout?: number }`, 粘进来拿到 `FlagSchema`。然后启动时 `z.array(FlagSchema).parse(JSON.parse(fs.readFileSync('flags.json')))`, 配置错了在启动时崩, 不是在生产环境读到那条坏 flag 才崩。
在 Next.js / Astro 路由里校验 query 参数
`/search?q=&page=&category=` 路由读 `searchParams`, 你已经 把形状写成 `interface SearchParams { q: string; page?: number; category: 'all' | 'tools' | 'blog' }`。粘进来, 拿到 `SearchParamsSchema`, 用 `SearchParamsSchema.safeParse(Object.fromEntries(url.searchParams))`。 返回的是 `{ success: true, data } | { success: false, error }` 区分式联合, 直接喂给你的错误 UI。
让表单校验器和 DTO 类型严格对齐
前端表单 POST 到一个收 `CreateUserDto` 的接口。不希望表单 schema 和 DTO 漂走。把 DTO 粘进来, 拿到 `CreateUserDtoSchema`, 用 `zodResolver(CreateUserDtoSchema)` 喂给 react-hook-form。 后端在接口处加一行 `CreateUserDtoSchema.parse(req.body)`。同一份契约, 两 端都校验, 一个真相源。
TS 类型改了之后同步一个已经存在的 Zod schema
你把 `interface Order` 改了 (重命名字段、加了可选、把 union 收窄), 但现有的 `OrderSchema` 还是旧的。把新的 interface 粘进来, 把输出和旧 schema 对一遍 diff, 把差异 手工改过去。比一行一行对眼睛快, 也不会漏。
常见踩坑
TS 任何写法都期望 Zod 能表达。Zod 只校验运行时存在的东西。条件类型、mapped type、template literal type、`infer`、`keyof`、indexed access (`T[K]`) 都是编译期形状操纵, 运行时没有对应物。工具会在输出顶上以 "不支持, 需手工核对" warning 列出, 不会默默出错。
粘的代码从别的文件 import 类型。import 语句会被忽略。只有这段粘进来的声明能被解析。引用外部类型会落成 `z.unknown()` 并 warning。要么把相关声明都粘进来, 要么手工改输出加上 `import { UserSchema } from "./user"`。
忘了 Zod object 模式默认会默默删掉未知 key。工具默认带 `.strict()` 就是因为这条默认行为坑过太多人。想宽松解析 (吃第三方数据, 多余字段不在乎)? 切到 `.passthrough()`, 主动选择, 不是默认。
期望 `z.enum` 接 number 字面量。Zod 的 `z.enum([1, 2, 3])` 类型上过不去。设计上只接字符串。`1 | 2 | 3` 会出 `z.union([z.literal(1), z.literal(2), z.literal(3)])`。想要更紧的校验, 后面接 `.refine(v => [1,2,3].includes(v))`。
粘了一个没类型的 JS 文件然后吃 parse error。工具只解析 TypeScript 声明。顶层的 `function foo()` 或 `const x = 1` 会出 "no interface/type declaration found"。先把形状包成 `interface` 或 `type` 再粘。
用 `Pick<T, K>` / `Omit<T, K>` 时 K 不是字面量集合。只能解析字面量字符串 key (`Pick<User, "id" | "name">`); `Pick<T, keyof T>` 会回退到基础类型并 warning。动态 key 集合需要你手工拼出 schema (一般就是一行 `.pick({ id: true, name: true })`)。
隐私说明
你粘进来的 TypeScript 源码不会离开这个浏览器标签页。文本框 内容刻意不写进 URL。只有选项 (object 模式、schema 后缀、 infer-type 开关、extract-nested 开关) 通过 `useUrlState` 同步到 URL。这意味着 "分享配置" 链接给同事打开是一样的配 置, 但他粘自己的源码, 不会意外继承你的。token 化和解析都 是浏览器里跑的纯 JavaScript, 没有任何网络请求, 没有对文本 框内容做 analytics, 也不写 localStorage。粘内部 DTO、内部 API 契约、还没发布的 endpoint 规范、客户形状的类型都安全。 这些你本来就不会粘到第三方站。
常见问题
类似工具组合
做你这行的人, 还会一起用这些。