JavaScript 运行时类型检查需手动实现,TypeScript 提供编译期静态检查但不改变运行时行为,仍需结合运行时校验保障安全。

JavaScript 运行时类型检查只能靠手动判断
JavaScript 本身没有内置的静态类型系统,所有类型检查都发生在运行时,且必须显式编写逻辑。比如想确保某个参数是 string,就得写 typeof x === 'string' 或更严格的 typeof x === 'string' && x !== null && x !== undefined。
常见错误现象包括:Cannot read property 'trim' of undefined、x.map is not a function——这些都不是语法错误,而是在值不符合预期时才暴露的问题。
- 用
Array.isArray()替代typeof x === 'object'判断数组(后者对数组返回'object') - 检查可选链或空值合并前,先确认对象结构是否稳定,否则
obj?.user?.name ?? 'anon'可能掩盖深层类型错配 - 第三方 API 返回数据结构易变,仅靠
console.log()看一眼就写逻辑,极易漏掉字段缺失或类型漂移
TypeScript 不是新语言,而是带类型标注的 JavaScript 编译器
TypeScript 的核心价值不是“多了一套语法”,而是它把类型声明编译成纯 JavaScript 后完全擦除,不改变运行时行为。你写的 function greet(name: string): string,编译后就是 function greet(name) { ... },零运行时开销。
它成为行业标准的关键在于:和现有工程无缝衔接,且提供渐进式采用路径。
立即学习“Java免费学习笔记(深入)”;
- 已有 JS 项目可直接重命名
.js为.ts,再逐步添加类型注解,不需要一次性重写 -
tsc --noEmit可只做类型检查,不生成代码,方便集成进 CI 流程 - 支持 JSDoc 类型标注(如
/** @type {number[]} */),对不想引入 TS 构建链的团队也算友好过渡
TS 类型推导和 any 是最大陷阱来源
TypeScript 默认开启宽松推导,尤其在函数返回值、对象字面量、数组初始化等场景下容易隐式推导出 any 或过于宽泛的联合类型,反而掩盖问题。
典型表现:const res = await fetch('/api/user'); const data = await res.json(); // data: any —— 此时后续所有操作都失去类型保护。
- 启用
"noImplicitAny": true和"strict": true是底线配置,否则类型检查形同虚设 - 避免直接用
any或//@ts-ignore压制报错;应优先用unknown+ 类型守卫(如isString(x)) - 接口定义别偷懒写
interface User { [key: string]: any },这等于放弃类型约束
类型检查 ≠ 运行时安全,TS 无法替代边界校验
即使 TS 编译通过,也不能保证生产环境不出错。因为类型信息在编译后消失,而真实数据来自用户输入、网络响应、localStorage 等不可信源。
例如这个看似严谨的 TS 接口:
interface ApiResponse {
id: number;
name: string;
tags: string[];
}但后端可能返回 { id: "123", name: null, tags: "a,b,c" }——TS 对运行时数据结构无控制力。
- 关键路径(如表单提交、API 响应解析)仍需运行时校验,可用
zod或io-ts做 schema 验证 - 不要依赖 TS 类型做权限判断或业务规则(如
if (user.role === 'admin')),角色字段可能被篡改 - 构建时类型检查和部署后监控要并存:类型报错拦不住恶意请求,日志和 Sentry 报告才是最后一道防线
类型系统真正起效的前提,是团队对「哪些地方必须加类型」「哪些类型必须校验」有共识,并落实到 PR 检查和 CI 卡点里。否则,再多的 interface 和 as const 也只是装饰。











