普通视图

发现新文章,点击刷新页面。
今天 — 2026年1月23日首页

从编译期到运行时:TypeScript 和 Zod 的职责分工

作者 清妍_
2026年1月23日 16:56

在前端工程里,TypeScript 几乎已经成了默认配置。
类型提示、自动补全、编译期报错,极大提升了开发体验。

但随着项目开始接触更多运行时不确定的数据(接口返回、配置文件、iframe、AI 输出),一个问题逐渐显现:

TypeScript 的“类型安全”,只存在于编译期。

这也是 Zod 频繁出现在近几年项目和 demo 中的原因。


一、TS 和 Zod 各自解决什么问题?

先把两者的职责说清楚。

维度 TypeScript Zod
作用阶段 编译期 运行时
是否参与打包后代码 ❌ 不存在 ✅ 存在
是否校验真实数据
是否影响开发体验 ✅ 极强 ⚠️ 辅助
主要目标 防止你写错代码 防止数据把程序搞崩

一句话总结:

TS 约束“你怎么写代码”,
Zod 约束“程序实际接收到什么数据”。

两者不是替代关系,而是分工关系。


二、有了 TS,为什么还需要 Zod?

这是很多人第一次看到 Zod 时的自然疑问。

关键原因在于:
TS 是静态的,Zod 是运行时的。

1️⃣ TypeScript 只存在于编译期

type User = {
  name: string;
  age: number;
};

这段类型:

  • 在你写代码时存在
  • 在 IDE 里给你提示
  • 打包之后会被完全移除

也就是说,运行时根本不存在 User 这个概念


2️⃣ 一个非常常见的错误直觉(90% TS 新手都会这样)

type User = {
  name: string;
  age: number;
};

const user: User = JSON.parse(localStorage.getItem('user')!);

TS:✔️ 没问题
运行时:❓ 完全未知

为什么这是危险的?

因为 localStorage 里的内容可能是:

{ "name": "Alice", "age": "18" }

或者:

null

甚至:

"hacked"

但 TS 不会、也不可能在运行时帮你检查这些。


三、Zod 在这里解决了什么?

Zod 的核心价值只有一个:

在运行时,对真实数据做结构校验,并在失败时明确抛错。

同样的逻辑,用 Zod 写是这样的:

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
});

const raw = JSON.parse(localStorage.getItem('user')!);
const user = UserSchema.parse(raw);

如果数据不符合约定:

  • 立即抛出错误
  • 明确指出哪一项不合法
  • 不会让 bug 延迟到某个业务逻辑里才爆炸

这一步,TS 是完全做不到的


四、什么叫“不可信输入来源”?

简单说一句不抽象的定义:

任何不是你当前代码自己 new 出来的数据,都是不可信的。

在实际项目中,以下全部属于不可信输入:

  • JSON.parse(...)
  • fetch(...) / 接口返回
  • postMessage
  • localStorage
  • 第三方 SDK 返回值
  • iframe / Web Worker 通信
  • AI 模型返回的 JSON

这些数据的共同点是:

它们的真实形状,TS 在运行时一无所知。


五、一个更直观的“跨边界”例子

postMessage 场景

window.addEventListener('message', (event) => {
  const data = event.data;
});

在这里:

  • event.data 的类型是 any
  • TS 无法保证它来自谁
  • 也无法保证结构正确

如果你直接用:

data.type === 'LOGIN'
data.payload.userId

只要数据结构稍有变化,就会在运行时崩掉。


用 Zod 明确边界

const MessageSchema = z.object({
  type: z.literal('LOGIN'),
  payload: z.object({
    userId: z.string(),
  }),
});

window.addEventListener('message', (event) => {
  const msg = MessageSchema.parse(event.data);
  // 从这里开始,TS 才真正安全
});

这一步的意义是:

把“外部世界的数据”,转化成“TS 世界里可信的数据”。


六、Zod 一般会出现在什么项目里?

你在传统 CRUD 业务中很少看到 Zod,并不奇怪。

Zod 通常出现于这些场景:

  • BFF / Node 服务
  • 插件系统 / 扩展机制
  • 配置驱动系统
  • 微前端 / iframe 通信
  • AI / Agent / Tool 调用
  • MCP / function calling

它们的共同特征是:

数据频繁跨越系统、进程、运行时边界。


七、TS + Zod 的合理分工方式

一个成熟的工程里,两者的职责通常是:

  • Zod:守住边界

    • 校验所有外部输入
    • JSON、接口、消息、AI 输出
  • TypeScript:管理内部

    • 业务逻辑
    • 状态流转
    • 组件和函数之间的协作

可以用一句话概括:

Zod 负责“别让脏数据进来”,
TS 负责“进来之后别把代码写错”。

❌
❌