ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TypeScript 1.4 新特性详解:联合类型、let/const、类型守卫与编译选项实战指南

TypeScript 1.4 新特性详解:联合类型、let/const、类型守卫与编译选项实战指南 文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载导读本文基于 TypeScript 1.4 版本发布说明zh/release-notes/typescript-1.4.md展开系统讲解该版本引入的联合类型、严格的泛型检查、let/const声明、模板字符串、类型守卫、类型别名、const enum、-noEmitOnError编译选项与 AMD 模块命名等核心能力。读完本文你将掌握 TypeScript 1.4 时代的类型系统关键升级理解这些特性在现代 TypeScript 中的延续形态并能将其实战应用于接口建模、参数校验、枚举优化与构建配置。本文还结合本仓库的变量声明、联合类型与交叉类型、高级类型、枚举等手册章节补充了更深层的原理与用法说明。一、联合类型Union Types1.1 为什么需要联合类型在 JavaScript 与 TypeScript 的日常开发中一个值常常可能属于多种类型之一。例如一个命令行 API 参数既可以接收string也可以接收string[]甚至还可以是一个返回string的函数。TypeScript 1.4 引入的联合类型正是为表达这种“多选一”的场景而设计——它用竖线|分隔各个候选类型表示“该值的类型可以是其中任意一种”。以接口定义为例可以用联合类型精确建模RunOptionsinterface RunOptions { program: string; commandline: string[] | string | (() string); }这里的commandline字段类型是string[] | string | (() string)三者的联合。相比此前只能退而使用any的做法联合类型既保留了灵活性又收紧了类型边界——错误的调用会在编译期被拦截。1.2 联合类型的赋值规则给联合类型赋值非常直观只要该值满足联合类型中任意一个候选类型就可以赋给它。var opts: RunOptions /* ... */; opts.commandline -hello world; // OK是 string opts.commandline [-hello, world]; // OK是 string[] opts.commandline [42]; // Error数字不是字符串或字符串数组1.3 读取联合类型的公共属性读取联合类型值时只能访问所有候选类型共有的成员本仓库 zh/handbook/unions-and-intersections.md 中的 Bird/Fish 示例同样阐述了这一点。例如string和string[]都拥有length属性因此可以直接访问if (opts.length 0) { // OKstring 和 string[] 都有 length 属性 console.log(its empty); }从类型安全的角度理解若联合中某类型独有某个成员编译器无法确定运行时该值属于哪个候选类型访问就会报错。这也正是下一节“类型守卫”的用武之地。1.4 结合类型守卫使用联合类型使用typeof之类的运行时检查即类型守卫后TypeScript 会在分支内收窄联合类型从而安全地访问各自独有的能力function formatCommandline(c: string | string[]) { if (typeof c string) { return c.trim(); } else { return c.join( ); } }二、严格的泛型调用检查2.1 背景旧行为的问题联合类型让“多类型”场景有了统一的类型表达TypeScript 团队因此决定改进泛型调用的规范性。在 TypeScript 1.4 之前下面的代码编译时不会报错出乎意料地通过了function equalT(lhs: T, rhs: T): boolean { return lhs rhs; } // 之前没有错误 // 现在会报错在 string 和 number 之间没有最佳的基本类型 var e equal(42, hello);原因在于此前编译器会为T推断出一个过于宽松的“最佳基本类型”导致number与string两个不相关类型被强行统一。1.4 起这种调用会明确报错促使开发者显式表达意图。2.2 通过联合类型指定行为借助联合类型你可以在函数定义时或调用时精确指定泛型参数的行为// choose function where types must match —— 两个参数类型必须一致 function choose1T(a: T, b: T): T { return Math.random() 0.5 ? a : b; } var a choose1(hello, 42); // Errorstring 与 number 不匹配 var b choose1string | number(hello, 42); // OK显式指定 T 为联合类型 // choose function where types need not match —— 两个参数类型可以不同 function choose2T, U(a: T, b: U): T | U { return Math.random() 0.5 ? a : b; } var c choose2(bar, foo); // OKc: string var d choose2(hello, 42); // OKd: string | number从源码结构看choose2用两个独立的类型参数T、U并返回T | U正是联合类型在泛型签名中“承载不确定性”的典型用法这一模式在后续版本的 TypeScript 中被广泛沿用。2.3 更好的类型推断当数组等集合中混有多种类型的值时联合类型会显著改善类型推断var x [1, hello]; // x: Arraystring | number x[0] world; // OK x[0] false; // Errorboolean 不是 string 或 number元素类型被精确推断为string | number后续写入会被严格校验避免了此前退化为any[]的尴尬。三、let 声明块级作用域变量3.1 var 提升引发的陷阱在 JavaScript 里var声明会被“提升”到所在作用域的顶端这可能引发一些令人困惑的 bugconsole.log(x); // 本想写 y /* later in the same block */ var x hello;上面的代码不会报错console.log(x)只会输出undefined。更严重的是var是函数作用域的——在if块内声明的变量在块外也能访问多次声明同一变量也不会报错详见 zh/reference/variable-declarations.md 对var作用域规则的深入剖析包括经典的setTimeout循环闭包陷阱。3.2 let 的块级作用域与暂时性死区TypeScript 1.4 支持了 ES6 的let关键字用于声明块级作用域的变量。一个let变量只能在声明之后的位置被引用且作用域仅限于声明它的块if (foo) { console.log(x); // Error不能在 x 声明之前引用它 let x hello; } else { console.log(x); // Errorx 未在此块中声明 }此外let声明不允许在同一个作用域内重复声明同名变量也不能与函数参数或var声明冲突这些规则在 zh/reference/variable-declarations.md 的“重声明及屏蔽”一节有完整演示。3.3 使用前提目标必须为 ES6注意历史性前提let只在设置编译目标为 ECMAScript 6--target ES6时生效。在 ES5 及更早目标下编译需要配合转译工具或接受不支持的结果。现代 TypeScript如 5.x已将let/const转译至任意目标这一限制早已解除但理解其历史脉络有助于阅读旧代码。四、const 声明不可重新赋值的常量const是 TypeScript 1.4 支持的另一个 ES6 声明类型。不能给const变量重新赋值只能在声明时初始化这对于那些初始化后不希望被改变的值非常有帮助const halfPi Math.PI / 2; halfPi 2; // Error不能给 const 变量赋值与let一样const也是块级作用域的且只在--target ES6下生效。需要澄清的是const保证的是“绑定不可重新赋值”而非“值不可变”——对象内部属性仍可修改正如 zh/reference/variable-declarations.md 中kitty.name Rory的示例所示若需属性级只读应使用 TypeScript 的只读修饰符。现代 TypeScript 还引入了const断言与as const进一步提升常量语义的精确度。五、模板字符串TypeScript 1.4 支持 ES6 模板字符串可以方便地在字符串中嵌入任意表达式var name TypeScript; var greeting Hello, ${name}! Your name has ${name.length} characters;当编译目标为 ES6 之前的版本时模板字符串会被编译器自动降级分解为普通字符串拼接var name TypeScript!; var greeting Hello, name ! Your name has name.length characters;这意味着即使运行环境尚不支持 ES6也能安全使用模板字符串语法。现代手册中模板字符串类型Template Literal Types更被扩展为一种强大的类型操作工具见 zh/handbook-v2/type-manipulation/template-literal-types.md。六、类型守卫Type Guards6.1 typeof 检查JavaScript 常用模式之一是在运行时用typeof或instanceof检查表达式的类型。TypeScript 1.4 起编译器能够识别if语句中的这类条件并随之改变类型推断结果var x: any /* ... */; if (typeof x string) { console.log(x.subtr(1)); // Errorsubtr 不存在于 string 类型上 } // x 在 if 之外仍然是 any x.unknown(); // OK6.2 typeof 结合联合类型与 else类型守卫与联合类型组合时威力尽显——if分支收窄到一个候选类型else分支自动收窄到其余候选类型var x: string | HTMLElement /* ... */; if (typeof x string) { // 此处 x 是 string如上所示 } else { // 此处 x 是 HTMLElement console.log(x.innerHTML); }6.3 instanceof 结合类与联合类型instanceof同样具备收窄能力class Dog { woof() { } } class Cat { meow() { } } var pet: Dog | Cat /* ... */; if (pet instanceof Dog) { pet.woof(); // OK } else { pet.woof(); // Error此分支 pet 是 Cat }这一机制在 zh/reference/advanced-types.md 的“类型守卫与类型区分”一节中被系统化展开除了typeof/instanceof内置守卫还可以通过“类型谓词”如pet is Fish编写用户自定义类型守卫在现代 TypeScript 中这是处理可辨识联合discriminated unions的核心手段。七、类型别名Type Aliases从 TypeScript 1.4 起可以使用type关键字为类型定义“别名”type PrimitiveArray Arraystring | number | boolean; type MyNumber number; type NgScope ng.IScope; type Callback () void;类型别名与其原始类型完全一致只是简单的替代名——它不创建新类型任何使用原类型的地方都可以用别名替换反之亦然。别名尤其适合为冗长的联合类型命名、为回调签名起语义化名称、或包装第三方类型如上面的ng.IScope。现代 TypeScript 进一步赋予type强大的结构化能力映射类型、条件类型、模板字面量类型等但“别名即替代名”这一核心语义贯穿至今。八、const enum完全嵌入的枚举8.1 与普通枚举的区别枚举很有用但有些程序并不需要枚举生成的运行时对象而是希望把枚举成员对应的数字值直接替换内联到使用处。const enum声明在类型安全方面与普通enum完全一致区别在于编译时会清除掉枚举对象本身const enum Suit { Clubs, Diamonds, Hearts, Spades, } var d Suit.Diamonds;编译结果恰好是var d 1;没有生成任何枚举查找表Suit.Diamonds直接内联为数值1减少了运行时开销与产物体积。普通enum的完整运行形态反向映射、字符串枚举、异构枚举等可参考 zh/handbook/enums.md。8.2 编译期的常量表达式求值TypeScript 还会在可能的情况下于编译期求值枚举表达式enum MyFlags { None 0, Neat 1, Cool 2, Awesome 4, Best Neat | Cool | Awesome, } var b MyFlags.Best; // emits var b 7;这里Best被编译期计算为1 | 2 | 4 7体现了 zh/handbook/enums.md 所讲的“常量枚举表达式”常量成员可由字面量、其他常量枚举成员及其按位运算组合而成这一规则。经典的按位标志位组合正是位运算枚举的实际应用场景。九、-noEmitOnError 命令行选项9.1 默认行为与痛点TypeScript 编译器的默认行为是即使存在类型错误比如把string赋值给number仍然会生成.js文件。在构建服务器或需要“纯净构建”的场景下这是不希望看到的——带错的产物可能被继续打包部署。9.2 noEmitOnError 的语义新的noEmitOnError标记可以阻止编译器在遇到错误时继续生成.js代码tsc --noEmitOnError src/main.ts该选项可通过命令行传入也可写入tsconfig.json{ compilerOptions: { noEmitOnError: true } }9.3 MSBuild 默认启用发布说明特别指出noEmitOnError是 MSBuild 工程的默认行为这保证了 MSBuild 持续构建输出的永远是来自纯净构建的产物。这一语义在现代 TypeScript 中仍是tsc --noEmitOnError的标准配置与--noEmit完全只检查不输出形成互补。十、AMD 模块名amd-module 标签10.1 匿名 AMD 模块的问题默认情况下TypeScript 生成的 AMD 模块是匿名的即define调用不带模块名。这在配合其他工具比如 r.js 优化器处理生成模块时可能带来麻烦——匿名模块难以被外部按名引用或合并。10.2 通过标签指定模块名新的amd-module name标签允许给编译器传入一个可选模块名写在模块文件顶部//// [amdModule.ts] ///amd-module nameNamedModule/ export class C {}编译结果会把NamedModule作为模块名传入 AMD 的define调用//// [amdModule.js] define(NamedModule, [require, exports], function (require, exports) { var C (function () { function C() {} return C; })(); exports.C C; });这样生成的模块便有了稳定的全局标识便于 r.js 等构建工具按名合并、压缩与加载。注意///三斜线指令的写法与官方约定它与本文前述的--target、--noEmitOnError一样都是编译器层面的配置手段。结语TypeScript 1.4 是一个承前启后的重要版本联合类型、严格的泛型检查与更好的类型推断重塑了类型系统对“多类型”场景的表达能力let/const、模板字符串让开发者提前享受 ES6 语法红利类型守卫、类型别名与const enum分别在收窄、命名与性能三个维度补齐了日常开发的拼图noEmitOnError与 AMD 模块名则体现了对构建流程与工具链生态的深入考量。这些特性在今天的 TypeScript本仓库手册覆盖至 6.0中大多以更完善的形态延续理解其源头与设计动机将帮助你更透彻地把握现代 TypeScript 的类型体系与编译模型。延伸阅读zh/release-notes/README.md全部版本发布说明索引zh/reference/variable-declarations.mdvar/let/const的完整语义与解构zh/handbook/unions-and-intersections.md联合类型与交叉类型的现代手册讲解zh/reference/advanced-types.md类型守卫、类型谓词与高级类型收窄zh/handbook/enums.md枚举的常量/计算成员与运行时形态赞分享文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载相关推荐Dagger TypeScript SDK 的 EngineCacheEntry 类本地引擎缓存条目的观测与清理指南Dagger TypeScript SDK 的 EngineCacheEntry 类本地引擎缓存条目的观测与清理指南 EngineCacheEntry 是 D文档教程Docker-alpine-glibc CI/CD集成使用GitHub Actions自动化构建与发布终极指南 Docker alpine glibc CI/CD集成使用GitHub Actions自动化构建与发布终极指南 想要快速掌握Docker alpine如何掌握RedwoodJS联合类型类型守卫与类型收窄实用指南如何掌握RedwoodJS联合类型类型守卫与类型收窄实用指南 RedwoodJS是一个全栈JavaScript框架它结合了React、GraphQL和Pri后端前端Web框架开发工具上一篇终极指南如何使用Firebase PHP JWT实现安全身份认证下一篇CANN易用DSL闪存注意力内核创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表