TypeScript 的学习资料很是多,其中也不乏不少优秀的文章和教程。可是目前为止没有一个我特别满意的。缘由有:前端
所以个人想法是作一套不一样市面上大多数的 TypeScript 学习教程。以人类认知的角度思考问题,学习 TypeScript,经过通俗易懂的例子和图片来帮助你们创建 TypeScript 世界观。 而本篇文章则是这个系列的开篇。git
系列安排:github
目录未来可能会有所调整。
注意,个人系列文章基本不会讲 API,所以须要你有必定的 TypeScript 使用基础,推荐两个学习资料。typescript
结合这两个资料和个人系列教程,掌握 TypeScript 指日可待。编程
接下来,咱们经过几个方面来从宏观的角度来看一下 TypeScript。数组
<!-- more -->app
上一节的上帝视角看 TypeScript,咱们从宏观的角度来对 Typescript 进行了一个展望。之因此把那个放到开头讲是让你们有一个大致的认识,不想让你们一叶障目。当你对整个宏观层面有了必定的了解,那么对 Typescript 的理解就不会错太多。相反,一开始就是具体的概念和 API,则极可能会让你丧失都总体的基本判断。函数
实际上, Typescript 一直在不断更新迭代。一方面是由于当初许下的诺言”Typescript 是 JavaScript 的超集“(JavaScript 的特性你要同步支持,同时也要处理各类新语法带来的不兼容状况)。不单是 ECMA,社区的其余发展可能也会让 Typescript 很难受。 好比 JSX 的普遍使用就给 Typescript 泛型的使用带来了影响。学习
TypeScript 一直处于高速的迭代。除了修复平常的 bug 以外,TypeScript 也在不断发布新的功能,好比最新 4.0.0 beta 版本的标签元祖 的功能就对智能提示这块颇有用。Typescript 在社区发展方面也作的格外好,以致于它的竞争对手 Flow 被 Typescript 完美击败,这在很大程度上就是由于 Typescript 没有烂尾。现在微软在开源方向的发力是愈来愈显著了,我很期待微软接下来的表现,让咱们拭目以待。spa
有的同窗可能有疑问, JavaScript 不是也有类型么? 它和 Typescript 的类型是一回事么?JavaScript 不是动态语言么,那么通过 Typescript 的限定会不会丧失动态语言的动态性呢?咱们继续往下看。
记住这两句话,咱们接下来解释一下这两句话。
对于 JavaScript 来讲,一个变量能够是任意类型。
var a = 1; a = "lucifer"; a = {}; a = [];
上面的值是有类型的。好比 1 是 number 类型,"lucifer" 是字符串类型, {} 是对象类型, [] 是数组类型。而变量 a 是没有固定类型的。
对于 Typescript 来讲, 一个变量只能接受和它类型兼容的类型的值。提及来比较拗口, 看个例子就明白了。
var a: number = 1; a = "lucifer"; // error var b: any = 1; a = "lucifer"; // ok a = {}; // ok a = []; // ok
咱们不能将 string 类型的值赋值给变量 a, 由于 string 和 number 类型不兼容。而咱们能够将 string,Object,Array 类型的值赋值给 b,所以 它们和 any 类型兼容。简单来讲就是,一旦一个变量被标注了某种类型,那么其就只能接受这个类型以及它的子类型。
类型和值居住在不一样的空间,一个在阳间一个在阴间。他们之间互相不能访问,甚至不知道彼此的存在。类型不能当作值来用,反之亦然。
以下代码会报类型找不到的错:
const aa: User = { name: "lucifer", age: 17 };
这个比较好理解,咱们只须要使用 interface 声明一下 User 就行。
interface User { name: string; age: number; } const aa: User = { name: "lucifer", age: 17 };
也就是说使用 interface 能够在类型空间声明一个类型,这个是 Typescript 的类型检查的基础之一。
实际上类型空间内部也会有子空间。咱们能够用 namespace(老)和 module(新) 来建立新的子空间。子空间之间不能直接接触,须要依赖导入导出来交互。
好比,我用 Typescript 写出以下的代码:
const a = window.lucifer();
Typescript 会报告一个相似Property 'lucifer' does not exist on type 'Window & typeof globalThis'.
的错误。
实际上,这种错误并非类型错误,而是找不到成员变量的错误。咱们能够这样解决:
declare var lucifer: () => any;
也就是说使用 declare 能够在值空间声明一个变量。这个是 Typescript 的变量检查的基础,不是本文要讲的主要内容,你们知道就行。
明白了 JavaScript 和 TypeScript 类型的区别和联系以后,咱们就能够来进入咱们本文的主题了:类型系统。
TypeScript 官方描述中有一句:TypeScript adds optional types to JavaScript that support tools for large-scale JavaScript applications。实际上这也正是 Typescript 的主要功能,即给 JavaScript 添加静态类型检查。要想实现静态类型检查,首先就要有类型系统。总之,咱们使用 Typescript 的主要目的仍然是要它的静态类型检查,帮助咱们提供代码的扩展性和可维护性。所以 Typescript 须要维护一套完整的类型系统。
类型系统包括 1. 类型 和 2.对类型的使用和操做,咱们先来看类型。
TypeScript 支持 JavaScript 中全部的类型,而且还支持一些 JavaScript 中没有的类型(毕竟是超集嘛)。没有的类型能够直接提供,也能够提供自定义能力让用户来本身创造。 那为何要增长 JavaScript 中没有的类型呢?我举个例子,好比以下给一个变量声明类型为 Object,Array 的代码。
const a: Object = {}; const b: Array = [];
其中:
上面说了类型和值居住在不一样的空间,一个在阳间一个在阴间。他们之间互相不能访问,甚至不知道彼此的存在。
使用 declare 和 interface or type 就是分别在两个空间编程。好比 Typescript 的泛型就是在类型空间编程,叫作类型编程。除了泛型,还有集合运算,一些操做符好比 keyof 等。值的编程在 Typescript 中更多的体现是在相似 lib.d.ts 这样的库。固然 lib.d.ts 也会在类型空间定义各类内置类型。咱们没有必要去死扣这个,只须要了解便可。
lib.d.ts 的内容主要是一些变量声明(如:window、document、math)和一些相似的接口声明(如:Window、Document、Math)。寻找代码类型(如:Math.floor)的最简单方式是使用 IDE 的 F12(跳转到定义)。
TypeScript 要想解决 JavaScript 动态语言类型太宽松的问题,就须要:
注意是变量,不是值。
第一个点是经过类型注解的语法来完成。即相似这样:
const a: number = 1;
Typescript 的类型注解是这样, Java 的类型注解是另外一个样子,Java 相似 int a = 1。 这个只是语法差别而已,做用是同样的。
第二个问题, Typescript 提供了诸如 lib.d.ts 等类型库文件。随着 ES 的不断更新, JavaScript 类型和全局变量会逐渐变多。Typescript 也是采用这种 lib 的方式来解决的。
(TypeScript 提供的部分 lib)
第三个问题,Typescript 主要是经过 interface,type,函数类型等打通类型空间,经过 declare 等打通值空间,并结合 binder 来进行类型诊断。关于 checker ,binder 是如何运做的,能够参考我第一篇的介绍。
接下来,咱们介绍类型系统的功能,即它能为咱们带来什么。若是上面的内容你已经懂了,那么接下来的内容会让你感到”你也不过如此嘛“。
好比定义 String 类型, 以及其原型上的方法和属性。
length, includes 以及 toString 是 String 的成员变量, 生活在值空间, 值空间虽然不能直接和类型空间接触,可是类型空间能够做用在值空间,从而给其添加类型(如上图黄色部分)。
interface User { name: string; age: number; say(name: string): string; }
这个是我自定义的类型 User,这是 Typescript 必须提供的能力。
这个主要是用来判断类型是否正确的,上面我已经提过了,这里就不赘述了。
有时候你不须要显式说明类型(类型注解),Typescript 也能知道他的类型,这就是类型推导结果。
const a = 1;
如上代码,编译器会自动推导出 a 的类型 为 number。还能够有连锁推导,泛型的入参(泛型的入参是类型)推导等。类型推导还有一个特别有用的地方,就是用到类型收敛。
接下来咱们详细了解下类型推导和类型收敛。
let a = 1;
如上代码。 Typescript 会推导出 a 的类型为 number。
若是只会你这么写就会报错:
a = "1";
所以 string 类型的值不能赋值给 number 类型的变量。咱们可使用 Typescript 内置的 typeof 关键字来证实一下。
let a = 1; type A = typeof a;
此时 A 的类型就是 number,证实了变量 a 的类型确实被隐式推导成了 number 类型。
有意思的是若是 a 使用 const 声明,那么 a 不会被推导为 number,而是推导为类型 1。即值只能为 1 的类型,这就是类型收敛。
const a = 1; type A = typeof a;
经过 const ,咱们将 number 类型收缩到了 值只能为 1 的类型。
实际状况的类型推导和类型收敛要远比这个复杂, 可是作的事情都是一致的。
好比这个:
function test(a: number, b: number) { return a + b; } type A = ReturnType<typeof test>;
A 就是 number 类型。 也就是 Typescript 知道两个 number 相加结果也是一个 number。所以即便你不显示地注明返回值是 number, Typescript 也能猜到。这也是为何 JavaScript 项目不接入 Typescript 也能够得到类型提示的缘由之一。
除了 const 能够收缩类型, typeof, instanceof 都也能够。 缘由很简单,就是Typescript 在这个时候能够 100% 肯定你的类型了。 我来解释一下:
好比上面的 const ,因为你是用 const 声明的,所以 100% 不会变,必定永远是 1,所以类型能够收缩为 1。 再好比:
let a: number | string = 1; a = "1"; if (typeof a === "string") { a.includes; }
if 语句内 a 100% 是 string ,不能是 number。所以 if 语句内类型会被收缩为 string。instanceof 也是相似,原理如出一辙。你们只要记住Typescript 若是能够 100% 肯定你的类型,而且这个类型要比你定义的或者 Typescript 自动推导的范围更小,那么就会发生类型收缩就好了。
本文主要讲了 Typescript 的类型系统。 Typescript 和 JavaScript 的类型是很不同的。从表面上来看, TypeScript 的类型是 JavaScript 类型的超集。可是从更深层次上来讲,二者的本质是不同的,一个是值的类型,一个是变量的类型。
Typescript 空间分为值空间和类型空间。两个空间不互通,所以值不能当成类型,类型不能当成值,而且值和类型不能作运算等。不过 TypeScript 能够将二者结合起来用,这个能力只有 TypeScript 有, 做为 TypeScript 的开发者的你没有这个能力,这个我在第一节也简单介绍了。
TypeScript 既会对变量存在与否进行检查,也会对变量类型进行兼容检查。所以 TypeScript 就须要定义一系列的类型,以及类型之间的兼容关系。默认状况,TypeScript 是没有任何类型和变量的,所以你使用 String 等都会报错。TypeScript 使用库文件来解决这个问题,最经典的就是 lib.d.ts。
TypeScript 已经作到了足够智能了,以致于你不须要写类型,它也能猜出来,这就是类型推导和类型收缩。固然 TypeScript 也有一些功能,咱们以为应该有,而且也是能够作到的功能空缺。可是我相信随着 TypeScript 的逐步迭代(截止本文发布,TypeScript 刚刚发布了 4.0.0 的 beta 版本),必定会愈来愈完善,用着愈来愈舒服的。
咱们每一个项目的须要是不同的, 简单的基本类型确定没法知足多样的项目需求,所以咱们必须支持自定义类型,好比 interface, type 以及复杂一点的泛型。固然泛型很大程度上是为了减小样板代码而生的,和 interface , type 这种刚需不太同样。
有了各类各样的类型以及类型上的成员变量,以及成员变量的类型,再就加上类型的兼容关系,咱们就能够作类型检查了,这就是 TypeScript 类型检查的基础。TypeScript 内部须要维护这样的一个关系,并对变量进行类型绑定,从而给开发者提供类型分析服务。
你们也能够关注个人公众号《脑洞前端》获取更多更新鲜的前端硬核文章,带你认识你不知道的前端。
公众号【 力扣加加】
知乎专栏【 Lucifer - 知乎】
点关注,不迷路!