├── .gitignore ├── LICENSE ├── README.md ├── assets ├── chapter1 │ ├── hierarchy.png │ ├── research.png │ └── subtypes.png ├── chapter2 │ ├── named_tuple.gif │ ├── tuple_argument.png │ ├── tuple_index.png │ └── tuple_length.png ├── chapter3 │ ├── check.png │ ├── report.png │ └── uppercase.gif ├── chapter4 │ ├── demo.gif │ └── trpc.gif └── chapter5 │ ├── effective_typescript.png │ ├── learning_typescript.png │ └── string_ts.gif ├── chapter1.md ├── chapter2.md ├── chapter3.md ├── chapter4.md └── chapter5.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 你可能不知道的 TypeScript 2 | 3 | ## 前言 4 | 5 | 欢迎你,体操家!本文将从实用角度出发,介绍 TypeScript 中的许多可能不为人所知的理论和特性,希望能够通过这种方式尽可能地抹平我们关于 TypeScript 的一些进阶知识和技巧的信息差,并启发我们使用 TypeScript 解决生产实践中的一些看似无法解决的类型问题。 6 | 7 | 本文不是所谓的「类型体操」指南。在介绍各种内容时,我会侧重于揭露它的生产价值。我不会涉及很多理论价值高于生产价值的高级技巧,例如使用类型系统写一个正则表达式的 Parser,或者是写一个五子棋游戏。 8 | 9 | 本文欢迎各位读者共同建设。如果你发现了表述不正确的地方,或者有一些好的 good idea,欢迎发表 issue。如果你觉得本文写得不错,欢迎转发和 star 哦! 10 | 11 | > 作者的博客上面还有很多好康的文章哦,虽然现在不怎么更新了:[https://darkyzhou.net](https://darkyzhou.net) 12 | 13 | ## 目录 14 | 15 | > [!NOTE] 16 | > 推荐在阅读时点击文件右上角的大纲按钮(编辑按钮右边那个)来展示章节的大纲,这样有助于理解章节内容 17 | 18 | - [第一章:基础知识](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter1.md) 19 | - [第二章:进阶话题](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter2.md) 20 | - [第三章:类型编程](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter3.md) 21 | - [第四章:生产实践](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter4.md) 22 | - [第五章:探索之路](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter5.md) 23 | 24 | ## 参考资料 25 | 26 | 本文的内容部分参考了下面的文章或书籍,没有它们的作者们的贡献就没有这篇文章。 27 | 28 | - [Handbook - The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) 29 | - [The type hierarchy tree](https://www.zhenghao.io/posts/type-hierarchy-tree) 30 | - [https://twitter.com/mattpocockuk](https://twitter.com/mattpocockuk) 31 | - [Transform Any Union in TypeScript with the IIMT](https://www.totaltypescript.com/immediately-indexed-mapped-type) 32 | - Effective TypeScript by Dan Vanderkam 33 | 34 | ## TODO 35 | 36 | 本文章编写过程较为仓促,我还有一些想写进来的话题: 37 | 38 | - 更多的生产实践 39 | - Optional Variance Annotations 以及函数参数的双向协变 40 | - 聊聊对象类型 41 | - `type` 和 `interface` 关键字的区别,包括隐式的 [index] 声明(忘记这个叫啥了) 42 | -------------------------------------------------------------------------------- /assets/chapter1/hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter1/hierarchy.png -------------------------------------------------------------------------------- /assets/chapter1/research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter1/research.png -------------------------------------------------------------------------------- /assets/chapter1/subtypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter1/subtypes.png -------------------------------------------------------------------------------- /assets/chapter2/named_tuple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter2/named_tuple.gif -------------------------------------------------------------------------------- /assets/chapter2/tuple_argument.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter2/tuple_argument.png -------------------------------------------------------------------------------- /assets/chapter2/tuple_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter2/tuple_index.png -------------------------------------------------------------------------------- /assets/chapter2/tuple_length.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter2/tuple_length.png -------------------------------------------------------------------------------- /assets/chapter3/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter3/check.png -------------------------------------------------------------------------------- /assets/chapter3/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter3/report.png -------------------------------------------------------------------------------- /assets/chapter3/uppercase.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter3/uppercase.gif -------------------------------------------------------------------------------- /assets/chapter4/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter4/demo.gif -------------------------------------------------------------------------------- /assets/chapter4/trpc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter4/trpc.gif -------------------------------------------------------------------------------- /assets/chapter5/effective_typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter5/effective_typescript.png -------------------------------------------------------------------------------- /assets/chapter5/learning_typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter5/learning_typescript.png -------------------------------------------------------------------------------- /assets/chapter5/string_ts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkyzhou/You-Might-Not-Know-TypeScript/c40dc1c3294946783955ef7959d9ea4fa1fd33e6/assets/chapter5/string_ts.gif -------------------------------------------------------------------------------- /chapter1.md: -------------------------------------------------------------------------------- 1 | | **目录** | **下一章** | 2 | | :----------: | :------: | 3 | | [你可能不知道的 TypeScript](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript#%E4%BD%A0%E5%8F%AF%E8%83%BD%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84-typescript) | [第二章:进阶话题](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter2.md) | 4 | 5 | --- 6 | 7 | # 第一章:基础知识 8 | 9 | ## 关于 TypeScript 10 | 11 | 早期的 JavaScript 应用普遍存在一个问题:开发效率难以随着团队规模的扩大而扩展(scale)。当时,来自微软的 Steve Lucco 等人认为解决问题的关键是一套类型系统,在它的基础上提供包括但不限于下面的能力: 12 | 13 | - 自动补全(Code Completion) 14 | - 跳转到定义(Go to Definition) 15 | - 安全的重构(Safe Refactoring) 16 | 17 | 当我们今天讨论 TypeScript 时,应该意识到它不仅仅是一个语言或者一个类型系统,它也是一套完整的 JavaScript 工具链,赋予了 IDE 分析 JavaScript/TypeScript 代码的能力。 18 | 19 | > TypeScript 和 VS Code 的诞生是相辅相成的。没有 TypeScript 带来的类型系统和上述的功能,就没有 VS Code 这个由多人团队构建的基于 Web 的大型应用程序。而 VS Code 的开发也为 TypeScript 带来了大量的改进反馈。TypeScript 和 VS Code 都是 2010 年代微软在 Web 上的投入计划的一环。 20 | 21 | 本文的主题是 TypeScript 的类型系统部分,并不涉及提供上述功能的部分,它被称为语言服务(language service)。因此,如果你在后文看到了「TypeScript」一词,它很可能指的是类型系统。 22 | 23 | ## 结构化类型(Structural Typing) 24 | 25 | 一个类型系统的重要属性是:它使用结构化类型(structural typing)还是名义类型(nominal typing)。这项属性决定了:当类型系统检查某个值是否能够被赋给(assign to)具有某个类型的变量时,它所使用的判据是什么。 26 | 27 | 对于名义类型,判据是值和变量的类型名称,就像下面的 Java 代码。 28 | 29 | ```java 30 | class Dog { 31 | public void walk() {} 32 | } 33 | 34 | class Duck { 35 | public void walk() {} 36 | } 37 | 38 | Dog dog; 39 | // 错误,Dog 和 Duck 是没有任何关系的类型,「狗就是狗,鸭就是鸭」 40 | dog = new Duck(); 41 | ``` 42 | 43 | 而对于结构化类型,判据是值和变量的类型结构,就像下面的 TypeScript 代码: 44 | 45 | ```java 46 | class Dog { 47 | public walk() {} 48 | } 49 | 50 | class Duck { 51 | public walk() {} 52 | } 53 | 54 | // 没有错误,因为狗和鸭的类型的结构一样(都由一个相同的 walk 函数构成) 55 | // 「因为都能够走路,所以狗和鸭一样」 56 | const dog: Dog = new Duck(); 57 | ``` 58 | 59 | > [!NOTE] 60 | > 你可能听说过[鸭子理论(Duck Typing)](https://en.wikipedia.org/wiki/Duck_typing),它可以说是结构化类型的思想的一种体现。 61 | > 62 | > Duck typing in computer programming is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine whether an object can be used for a particular purpose. 63 | > 64 | > With nominative typing, an object is of a given type if it is declared as such. With duck typing, an object is of a given type if it has all methods and properties required by that type. 65 | > 66 | > Duck typing may be viewed as a usage-based structural equivalence between a given object and the requirements of a type. 67 | 68 | TypeScript 的类型系统选择了结构化类型,这是出于兼容 JavaScript 生态的考虑。因为从人们使用 JavaScript 的方式来看,它更适合使用结构化类型去建模。这里举一个简单的例子: 69 | 70 | ```typescript 71 | function logPoint(p) { 72 | console.log(`${p.x}, ${p.y}`); 73 | } 74 | 75 | logPoint({ x: 12, y: 26 }); 76 | ``` 77 | 78 | 就像上面的 `logPoint` 一样,在人们编写的很多 API(特别是 DOM API 或者 JavaScript 语言内置的 API)中,人们只关心这个值是否存在一些发挥功能必要的属性。就像[你可以使用 `Array.from({ length: 10 })` 创建定长数组](https://darkyzhou.net/articles/js-array-creation)一样,JavaScript 并不关心你传入的参数是否真的是一个数组,它只关心发挥功能所必需的 `length` 属性。如果 TypeScript 采用名义类型,则需要为这些 API 的参数提供大量的内置类型,这样的做法无疑提高了 TypeScript 接入 JavaScript 的现有 API 的复杂度。 79 | 对于已经习惯了采用的名义类型的语言(大多数的面向对象语言,比如 Java)的人来说,结构化类型有时候会给他们带来一些意想不到的惊喜,比如他们可能会惊讶于下面的例子: 80 | 81 | ```typescript 82 | interface MyInterface { 83 | // 空接口 84 | } 85 | 86 | // 不报错! 87 | const a: MyInterface = "seele"; 88 | // 也不报错! 89 | const b: MyInterface = () => {}; 90 | ``` 91 | 92 | 不过,结构化类型赋予了 TypeScript 的类型系统非常强大的功能,让我们可以通过编程的方式「组合」出自己想要的类型,这一点在后续的类型编程中会详细讨论。 93 | 94 | > [!NOTE] 95 | > 虽然我们说 TypeScript 的类型系统采用了结构化类型,但这不是绝对的。在一些细节上,它采用了名义类型,比如对于 `class` 中使用 `private` 或 `protected` 修饰的属性:[https://github.com/microsoft/TypeScript/wiki/FAQ#when-and-why-are-classes-nominal](https://github.com/microsoft/TypeScript/wiki/FAQ#when-and-why-are-classes-nominal)。 96 | > 97 | > 此外,我们会在后文看到,仍然可以通过一些特殊的手段在 TypeScript 的类型系统中模拟出名义类型的效果,来达到一些需要名义类型才能实现的目的。 98 | 99 | ## 类型系统的目的 100 | 101 | [TypeScript 的设计目标(design goals)的第一条](https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals#goals): 102 | 103 | > Statically identify constructs that are likely to be errors. 104 | 105 | 我认为这是在说 TypeScript 应该为程序员提供一些手段,让他们在编码或编译时就能识别出各种结构的错误。所谓的「结构」可以理解为包括但不局限于以下的内容: 106 | 107 | - 函数的返回值必须是一个 `Promise`,且它 resolve 之后返回的值必须是个字符串 108 | - 函数的两个入参必须是长度相同的数组 109 | - 对象要么含有 `A` 属性要么含有 `B` 属性,不能同时含有、也不能都不含有 110 | - 若干个对象必须含有相同的键 111 | - 字符串必须包含若干个特定子串 112 | 113 | 从上面的内容可以看出,在 TypeScript 的视野中,标注并检查符号的原始类型只是它目的的一个方面。TypeScript 的团队在这十多年来不断地追求着更为宏大的设计目标。我们会在后文介绍如何利用 TypeScript 实现这些复杂的规则。 114 | 115 | TypeScript 想要为这些「结构(construct)」提供一种在编译期就能够进行自动化检查的手段,从而避免过去人们使用 JavaScript 时将很多编码错误(不局限于类型错误)泄漏到运行时,带来不必要的损失。 116 | 换句话说,TypeScript 的目的是提供一种自动化的工具,对代码进行广义上的静态检查,只不过具体的检查规则需要程序员接入(opt in)到代码中的对应部分。如果程序员什么规则都不施加,那么一段 TypeScript 代码就跟 JavaScript 代码无异,这也在一定程度上解释了为什么 [TypeScript 的仓库介绍里说「TypeScript is a superset of JavaScript」](https://github.com/microsoft/typescript)。 117 | 118 | TypeScript 提供的自动化检查对于团队协作来说是一个可扩展(scalable)的方案,因为它将过去的很多通过注释、文档和口口相传的「结构」固化在了代码中,并且不依赖人就能检查这种「结构」的完整性。毕竟相比起记性很差、非常粗心的人来说,死板的规则有时候更适合做这类事情。当然,TypeScript 不能解决所有的「结构」问题,因为这不仅仅是编程语言层面的问题。 119 | 120 | > [!NOTE] 121 | > **扩展性(scalability)是我的个人见解** 122 | > 123 | > 我在评估某个解决方案时,会考察它在时间和空间两个维度上的扩展性: 124 | > 125 | > - 时间维度:时间的流逝等 126 | > - 空间维度:团队人员的变动,包括规模的扩大、成员的改变等 127 | > 128 | > 当我们说传统的基于注释、文档和 CR 等方法维护「结构」的方案扩展性不佳时,我们是在说: 129 | > 130 | > - 当时间流逝时,团队成员会不断忘记大量的注释和文档,导致方案效果弱化 131 | > - 当团队人员变动时,需要花费更多人力在理解注释、文档和进行 CR 上才能确保方案效果的持续 132 | > 133 | > 当我们说 TypeScript 提供的方案是可扩展的时候,我们基于以下理由: 134 | > 135 | > - 当结构的规则被完成后,它通过 TypeScript 的编译检查确保效果的实施,不依赖于人力的变化 136 | > - 当结构的规则被完成后,无论时间如何流逝,这个规则的效果并不会发生改变 137 | 138 | ## 类型是值的集合 139 | 140 | 在 TypeScript 的类型系统中,我们最好将所谓的「类型」理解为「值的集合」,即一个类型的本质是它所框定的值的集合。基于这个定义有: 141 | 142 | - 如果一个类型是另一个类型的子集,那么称前者是后者的子类型(subtype) 143 | - 如果一个类型是全集,那么其它所有类型都是它的子类型 144 | - 如果一个类型是空集,那么它是其它所有类型的子类型 145 | 146 | 在 TypeScript 对赋值语句 `a = b` 进行类型检查时,它会检查 `b` 的类型是不是 `a` 的子类型。如果 `a` 的类型是全集,那么这个赋值总是会通过检查。如果 a 的类型是空集,那么这个赋值总是无法通过检查。对应到具体的类型来说,上述的「全集」指的是 `any` 和 `unknown` 而「空集」指的是 `never`。 147 | 148 | 如果使用箭头表示类型的父子关系,可以得到下面的这张图: 149 | 150 |
151 |
152 |
180 |
181 |
338 |
339 |
243 |
244 |
368 |
369 |
534 |
535 |
99 | : Params;
100 | ```
101 |
102 | 对于路由定义 `/users/:userId@number/books/:bookId@number`,上述的 `ParseRouteString` 的返回类型为:`["userId", number] | ["bookId", number]`。接下来的问题是如何将它转换为期望的对象类型。
103 |
104 | ```typescript
105 | type MakeParamsType<
106 | T extends string,
107 | R extends [string, unknown] = ParseRouteString
689 |
699 | Oups! An error occured {res.data.content}
123 | = { [ERROR]: S };
262 |
263 | type DoCheck
690 |
700 |
提供了 62 种改善 TypeScript 使用技巧的方式,让你摆脱一些关于 TypeScript 的常见误用。书中还讨论了 TypeScript 的许多并没有在文档中介绍得清楚的机制,例如 Type Narrowing 和 Type Widening,帮助你理清 TypeScript 的一些设计原则和机制细节。
总的来说,这是一本在闲暇之余可以读读看的好书。
注意:此书第一版发布于 2019 年底,至今已经接近 4 年,在这个过程中 TypeScript 已经发生了很多新的改变。书中讨论的一些问题已经有了更好、更现代的解法,可以参考本文章来形成互补。 |
补充 TypeScript 基础知识的好书,涵盖了很多 TypeScript 官方文档没有涉及或讲得不多的内容,尤其是其中的:
本书的发布日期非常新,于 2022 年 7 月发行第二版,可以说是目前入门 TypeScript 的首选好书。 |
58 |
59 | ## 类型库
60 |
61 | 下面是一些能够帮助我们编写类型的工具库,注意这些库提供的 API 大多数都是 TypeScript 类型,所以并不会出现在编译产物中,也不会增加包体积。除了使用上的价值外,这些类型库还有学习上的价值,当我们对 TypeScript 的某个类型或功能不了解时,可以查看这些库的源码实现,从中获取思路。
62 |
63 | ### [ts-typesafe-decorators](https://github.com/sorgloomer/ts-typesafe-decorators)
64 |
65 | 为旧的 Stage 2 装饰器提供类型检查的工具类型库,本文在生产实践中[类型安全的装饰器](https://github.com/darkyzhou/You-Might-Not-Know-TypeScript/blob/main/chapter4.md#%E7%B1%BB%E5%9E%8B%E5%AE%89%E5%85%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8-50)一节就是受到了这个库的启发。它同样依赖于 TypeScript 5.0 或以上版本,所以又多了一个理由升级 TypeScript。
66 |
67 | ### [ts-essentials](https://github.com/ts-essentials/ts-essentials)
68 |
69 | 提供一些 TypeScript 没有自带但是很有用的工具类型。例如:
70 |
71 | - `XOR)
100 | .exhaustive();
101 | ```
102 |
103 | ### [ts-reset](https://github.com/total-typescript/ts-reset)
104 |
105 | - `fetch.json()` 和 `JSON.parse()` 会返回 `unknown` 而不是问题多多的 `any` 了
106 |
107 | - `Array.filter(Boolean)` 的返回值类型能够去掉空类型了
108 |
109 | ```typescript
110 | const input = [null, undefined, true, "seele"];
111 | // ^? const input: (string | boolean | null | undefined)[]
112 | const result = input.filter(Boolean);
113 | // ^? const result: (string | boolean)[]
114 | ```
115 |
116 | - 还有许多对 TypeScript 自带的类型库的改进
117 |
118 | ### [string-ts](https://github.com/gustavoguichard/string-ts)
119 |
120 | 针对字符串字面量类型的工具类型库,下面的图片来自它的 README。
121 |
122 |
124 |