TypeScript JSON 类型安全:解析、标注与运行时校验
JSON.parse 返回 any——类型安全的黑洞。本文讲解接口标注、类型断言的局限与类型守卫/校验库的运行时保障方案。
JSON.parse 的类型是 any,直接当接口用等于关闭类型检查。正确姿势分三层:接口描述期望形状、类型守卫或 Zod 在运行时验证、验证通过后才作为该类型使用。外部数据(API 响应、文件、localStorage)全部按此处理。
JSON 解析的类型现实
const data = JSON.parse(raw); // any——类型系统在这里断开
data.user.name; // 编译通过,运行时可能爆炸
any 的传染性:一个未校验的 parse 让下游全部"类型安全地"出错。
接口标注与断言的局限
interface ApiResponse { users: User[]; total: number; }
const resp = JSON.parse(raw) as ApiResponse; // 断言:编译器信了,运行时没保障
断言不验证任何东西——服务器改了字段、嵌套结构不符,断言照样放行。
类型守卫:运行时与编译期的桥
function isApiResponse(data: unknown): data is ApiResponse {
return (
typeof data === 'object' && data !== null &&
Array.isArray((data as any).users) &&
typeof (data as any).total === 'number'
);
}
const raw: unknown = JSON.parse(text);
if (isApiResponse(raw)) {
raw.users; // 收窄为 ApiResponse——运行时验证过的安全
}
生产方案:校验库
手写守卫在复杂结构下不可维护——Zod 生成"校验 + 类型"一体:
const ApiResponse = z.object({
users: z.array(User),
total: z.number(),
});
const resp = ApiResponse.parse(JSON.parse(text)); // 不符即抛错,符合即精确类型
分层防御策略
- 边界校验:所有外部数据入口(fetch、文件、localStorage、消息队列)过校验;
- 内部信任:校验后的数据在应用内部自由流动;
- 错误处理:校验失败走降级/告警路径——坏数据不进入业务逻辑。
常见问题(FAQ)
Q:localStorage 的数据也要校验吗?
要——用户可改、版本升级后结构可能漂移。所有"不信任边界"一视同仁。
Q:性能敏感路径的校验开销?
Zod/TypeBox 校验常规对象在微秒级——无感。数据管道场景用 TypeBox 编译模式。
Q:ts-json-schema-generator 类工具?
从 TS 类型生成 JSON Schema 是反向路线——与 Zod 的"Schema 生类型"哲学相反,两者选一避免双源。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。