TypeScript 如何做运行时校验
你或许有过这样的经历:用 JavaScript 写代码时,给函数传了个数字,结果本该接收字符串的地方突然乱码;或者从接口拿数据,本该是数组的字段,却被后台返回了空对象,导致页面直接报错。这些问题看似是“粗心”,实则是 JavaScript 本身的特性——它不会在运行前检查数据类型,而 TypeScript 虽然能在写代码时发现类型错误,却管不了运行阶段。
为什么 TypeScript 的类型声明管不了运行时?
很多人学过 TypeScript 后会疑惑:我明明给参数标了 string,为什么运行时还是能传数字?这是因为 TypeScript 的类型是“静态”的,只会在代码编译成 JavaScript 前生效,编译后就会被完全删掉——就像你在草稿纸上写的备注,写完就擦了,电脑根本不会看。

举个生活化的例子:你给外卖备注“要少糖的奶茶”,这是你和外卖店的“约定”,但外卖员实际送来的是全糖——约定只存在于你们沟通的那一刻,送到手上时,实际的甜度才是最终结果。TypeScript 的类型声明就像这份备注,只是给开发者看的规则,代码跑起来后,就只剩真实的数据了。
怎么补全这个漏洞?用运行时校验接住“意外数据”
要让 TypeScript 的“类型约定”在运行时也生效,得用专门的工具把“静态规则”变成“动态检查”。目前最常用的有两种方法,都能快速上手。
第一种是用类型校验工具,比如 Zod。它就像一个“数据安检员”,你先给它定好规则,它会在代码运行时逐一核对数据。比如要校验一个用户信息,你可以写这样的规则:
`javascript
import { z } from 'zod';
// 定义用户的校验规则:名字是字符串,年龄是18-100的数字
const UserSchema = z.object({
name: z.string(),
age: z.number().min(18).max(100)
});
// 校验接口返回的数据
const apiData = await fetch('/api/user').then(res => res.json());
// 如果数据符合规则,就用它;不符合,直接返回错误
const user = UserSchema.parse(apiData);
`
如果接口返回的年龄是15,Zod 会直接抛出错误,你不用等页面报错再找问题,代码一跑就能发现。
第二种是用运行时类型反射库,比如 ts-runtime,它能把 TypeScript 的类型声明直接转换成运行时的校验规则,不用额外写新代码。比如你写了一个 interface User,用 ts-runtime 就能自动把这个接口变成检查规则,相当于把草稿纸上的备注直接印成了必须遵守的标签。
日常开发的小技巧:别等错误出现才处理
运行时校验不用写得太复杂,日常开发只要注意两个小细节就行。一是对外部数据一定要校验:不管是接口返回、用户输入还是 localStorage 存的数据,都得当成“不可信的陌生人”,先查再用;二是校验后给数据做“类型断言”,告诉 TypeScript“这个数据我已经检查过,没问题”,这样后续代码就能用 TypeScript 的类型提示了。
还是用奶茶的例子:如果你自己去取餐,看到包装上写着“少糖”,就不用再问店员,直接拿了就走——运行时校验就是帮你确认包装上的字和实际奶茶一致,类型断言就是你心里确认“这杯确实是少糖的,我敢喝”。
这样做下来,你既能用上 TypeScript 写代码时的类型提示,又能避免运行时的奇怪报错,代码会稳很多。