类型建模与编译边界
TypeScript 在程序执行前检查我们声明的关系,JavaScript 在执行时处理真实值。类型系统能拒绝许多不一致用法,却不会自动验证网络数据、冻结对象或替服务端鉴权。学习类型建模的关键,是明确哪些信息仅存在于编译器,哪些语言特性会生成或保留运行时行为。
核心模型
TypeScript 在程序执行前检查我们声明的关系,JavaScript 在执行时处理真实值。类型系统能拒绝许多不一致用法,却不会自动验证网络数据、冻结对象或替服务端鉴权。学习类型建模的关键,是明确哪些信息仅存在于编译器,哪些语言特性会生成或保留运行时行为。
原理与机制
结构兼容不是精确对象验证
TypeScript 主要按成员结构判断兼容,类型名称相同与否通常不是关键。新鲜对象字面量有额外属性检查,先存到变量后传递可能按结构兼容通过,额外字段没有因此在运行时被删除。interface 适合对象契约和声明合并,type 还便于联合、元组等表达;并非谁全面更强。类型注解与多数断言会擦除,fetch 返回值写 as User 只是承诺。外部输入应先视为 unknown,执行真实校验并挑选允许字段;any 会绕过检查并把不确定性传播给后续代码。
收窄应来自真实检查,穷尽应反映状态空间
typeof、instanceof、in 和字面量比较把宽类型逐步收窄。unknown 是暂不能安全使用的值,never 表示不可能存在的值,void 则表达不使用返回结果,不能互换。把任务建成 idle/loading/success/error 的判别联合,让每支携带必需字段,再用 never 检测新增成员的遗漏。自定义 is 或 asserts 声明由编译器信任,实现不正确仍会失守。catch 可收到字符串或 null,至少先排除 null、核查 message 类型并兜底;跨 realm 的 Error 可能不通过当前 instanceof,getter/Proxy 读取本身也可能抛错。
类型关联与字段缺失都属于协议
type:A|B 与 payload:X|Y 独立声明会接受交叉错配;应构造 {type:A,payload:X}|{type:B,payload:Y},或从事件映射生成关联联合。泛型 K 若被放宽为联合,独立参数也可能丢配对约束,整体判别对象或关联元组更稳。并非任何解构都会丢关联,符合条件的 const 解构可保留控制流分析。补丁同样要明确缺失、undefined、null:exactOptionalPropertyTypes 让 x?:string 的存在值更严格,但读取仍可能 undefined;JSON 会省略对象中的 undefined,清空操作最好用明确 null 或操作类型。
enum 是类型擦除规则中的重要边界
普通 enum 通常生成运行时对象,数字枚举还有反向映射,字符串枚举不具同样行为。const enum 通常内联,减少对象,却把消费者产物绑定到编译时枚举值,跨包版本及 isolatedModules 可能出问题。库可选择普通 enum 或 as const 对象配合值联合;as const 不会调用 Object.freeze。若内部保留 const enum,需实际构建配合 preserveConstEnums,并在发布声明移除 const,让 JS 与声明一致。协议宜用明确稳定字符串,避免数字重排改变持久化含义。
可见性修饰与语言私有元素不是同一种保护
TS public 默认公开,protected 约束类及子类的常规访问,private 约束声明类的常规访问;它们主要提供静态软限制,普通属性编译后通常还在,private 也有方括号访问等逃生口。JavaScript #字段是独立私有元素,按声明名字与接收者品牌检查,不能用 obj["#x"] 取得,也不能由子类直接读基类私有名字。编译目标决定保留语法还是生成私有存储实现。#不保证返回的可变对象引用不可变,更不是秘密保险箱;浏览器中的封装不能替代服务端鉴权。
最小示例
typescript编译器预期接受 success 与 data 的配对,输出 JavaScript 后运行应显示“完成”。在联合里新增 cancelled 却不补分支,never 赋值应报错。直接把接口响应断言为 Result 不执行任何校验;示例故意只演示已验证内部状态的建模,不能作为解析外部 JSON 的完整实现。
环境:TypeScript 4.9+;建议 tsc --strict --noEmit 检查。本章可选属性实验另外开启 exactOptionalPropertyTypes。
核验:未执行教学示例;说明中的结果为机制推演,不是本轮测试通过记录。
边界与取舍
边界
- readonly、as const、private 主要是静态约束,不能自动冻结对象或保证数据真实。
- 缺失与显式 undefined 可被 Object.hasOwn 区分;?? 同时兜底 null 与 undefined,可能破坏清空协议。
- new Error 不是唯一异常来源;类型断言和错误类型谓词都不会补上缺少的运行时检查。
取舍
- 判别联合让非法组合更难构造,但后台刷新保留旧数据等真实并存状态也要明确建模,不能机械排除。
- 普通 enum 提供运行时对象;字符串常量对象更接近普通 JS 工具链,const enum 的产物收益需与发布兼容成本比较。
口述示范
我先讲清 TS 是结构化静态契约,再用判别联合和 never 保留状态及事件关联。外部 unknown 必须真实验证,可选字段还要和 JSON 协议一致。最后单独讨论会影响运行时的 enum 与 #字段,避免把擦除、封装或只读误说成安全保障。
章节练习
假设 TranslateFlow 的加载状态同时有 loading、error、data,如何使新增取消态暴露遗漏?
展开检查点
- 按合法业务状态建立 kind 联合,在 switch 末尾做 never 检查。
- 若允许旧数据后台刷新,显式表达;事件名称与负载用关联联合整体传递。
参考来源与核验边界
- TypeScript:Narrowing · 核验 2026-10-04
- TypeScript:Classes · 核验 2026-10-04
- TypeScript:Enums · 核验 2026-10-04
- TypeScript:exactOptionalPropertyTypes · 核验 2026-10-04
核验日期 2026-10-04。类型示例以 strict 检查为前提,exactOptionalPropertyTypes 需另行开启;关联 const 解构的控制流能力从 TS 4.6 起提供。不同编译目标与构建器输出应查看实际 JS,不推断所有 TS 语法都擦除。 本章新增示例未在本轮执行,不新增测试通过声明。
内容版本:2026-10-04.2 · 题目和来源 ID 保持原样,本站不将面经标签解释为企业官方出题或高频保证。