前端专栏 2019-11-22 19:17:55

对于前端从业者来说,TypeScript(以下简称 TS)已经不算是新技术。

Vue3 的源码基于 TS 编写, Angular 项目默认支持 TS 等。它出现的频率越来越高,而学习难度并不大,大概一个周末可以熟悉。

投入少,产出大,所以最好还是花点时间学习一下。

本文根据 TS handbook 整理出 TS 关键的知识点,并对某些部分作了扩展,希望能帮助大家学习理解。

前言

在学习 TS 之前,需要理解它的两个特点:

  1. TS 是 JS 的超集
  2. TS 给 JS 带来类型系统

这意味着 TS 的根基是 JS,是在 JS 的 基础上添加了类型系统。

类型声明

类型系统的一个特点是使用类型声明。

观察上述代码,在 JS 中,使用「等号=」给变量赋值。

经过 TS 的扩展,可以使用「冒号:」给变量赋类型。代码中声明变量 foo 的类型是 string。

类型校验

类型系统的另一个特点是进行类型校验。

在 TS 中,需要校验「等号=」左右的类型是否匹配。

如上述代码所示,值存在明确的类型,TS 会校验左右两侧的类型是否匹配,若不匹配则提示错误。

在了解这些前置知识后,来看看具体的 TS 知识点。

一、基本类型

继承 JS 的基本类型如:string、number、boolean、undefined、null。扩展了其他基本类型如:any、never、void。

1.1 string

表示类型为字符串

1.2 number

表示类型为数字

1.3 boolean

表示类型为布尔类型

1.4 undefined

表示类型为 undefined

1.5 null

表示类型为 null

1.6 void

表示类型为 undefined 或 null。

1.6.1 对于变量

一个声明为 void 类型的变量,只能被赋值为 undefined 或 null。这种应用场景较少。

1.6.2 对于函数

void 用于表示函数没有返回值,只是执行某些操作。这是 void 的普遍应用场景。

一个没有显式返回的函数,默认 return undefined。符合 void 类型只能被赋值为 undefined 或 null。

1.7 never

表示永远不存在值。

典型例子:一个只会抛出异常的函数,它的返回值并不存在。

执行函数则抛出错误,连 undefined 都不会返回。

1.8 any

表示可能为任何类型。

典型例子:不确定变量的类型或类型是动态的。

二、引用类型

TS 中的引用类型,除了 JS 中的数组类型、对象类型,还扩展了枚举类型,元祖类型。

2.1 数组类型

表示由某(些)类型组成的数组。有两种写法:方括号表示法和尖括号表示法。

2.1.1 方括号表示法

表示 arr 的类型是由数字组成的数组。

2.1.2 尖括号表示法

使用 Array<元素类型>,这是数组泛型的使用形式,关于泛型后续会展开。

2.2 只读数组

使用 ReadonlyArray<属性类型> 定义只读数组。只读数组只能在数组初始化时定义其值,创建后不能进行修改。

只读数组和常规数组类型 Array<T> 类似。区别在于:常规数组存在修改数组的方法,只读数组不存在修改数组的方法。

2.3 object

表示类型为对象。除了 string、number、bigint、boolean、 undefined、null、symbol 基本类型外的引用类型。

2.4 元组

由定长数组构成,数组中的元素是某(些)类型。

2.5 枚举

使用关键字 enum 定义枚举类型。默认枚举值从 0 开始,可以手动赋值。

三、类型断言

明确告诉 TS 某个值的类型。有两种写法:尖括号写法、as 写法。

尖括号写法

as 写法

注意事项

类型断言和类型转换是有明确区别,不能将它理解成类型转换。

在阐述此注意事项之前,先引入另一个概念:联合类型。

在上述代码中,string | number 表示的就是一个联合类型,意味着 answer 的类型可以为 string 或 number。

下面逐步解释类型断言和类型转换之间的区别。

上述代码中,string | number 联合类型包含 string 类型,所以这两种类型之间存在联系。使用 as 将联合类型断言成更加具体的 string 类型。

上述代码中,将 number 类型断言为 string | number 类型。同样是因为两种类型之间存在联系,所以也允许断言。相当于将一个具体的 number 类型断言成更加广泛的联合类型。

而将 string 类型断言为 number 类型,这是两种不同的类型,没有任何联系,断言会提示错误。

观察上述三个例子,断言发生在两种类型存在联系的情况,它并不是将一种类型转换成另一种类型。

有些脑瓜子灵活的朋友会想到,借助两次断言来进行类似的类型转换。

这是欺骗了 TS 校验,后果只能自己承担。

四、接口

上面提到使用 object 描述对象类型。但是,对于具有复杂结构的对象、函数。上述的 object 类型力有不逮。

上述代码中,即使是空对象,也能通过 object 类型校验,而不会校验对象的结构是否能满足后续使用。

此时,就需要使用接口。在 TS 中,接口是描述值的结构。

上述代码中,就定义了一个接口来描述参数 o,要求它是一个对象,含有 name 属性,且属性值是字符串。

所以,不符合此结构的空对象 {} 就提示错误。

一般来说,使用关键字 interface 来定义接口。

重写上述接口 ——

4.1 固定属性

在接口中,使用 属性名:属性类型 的结构定义固定属性。

如上述代码所示,传入的对象需要具有 name 和 age 两个属性,否则会报错。

4.2 可选属性

在接口中,使用 属性名?:属性类型 的结构定义可选属性。顾名思义,可选属性可以存在,也可以不存在。

4.3 只读属性

在接口中,使用 readonly 属性名:属性类型 的结构定义只读属性。只读属性只能在属性初始化时定义其值,定义后不能进行修改。

4.4 额外检查

TS 会对对象字面量进行额外的属性检查。

在上述代码中,接口 Point 定义了两个可选属性,对象字面量中属性 x 和接口兼容,属性 z 是多余无意义的。

虽然实际的属性比接口定义的多,按照常规理解,这是可以通过类型校验,但事实却相反。

TS 对于对象字面量是会进行额外的属性检查,体现在:

当对象字面量赋值给变量或它直接作为参数传递给函数时,如果对象字面量的属性没有在接口中定义,则会报错。

换句话说,对于对象字面量,当它直接赋值给变量和函数参数时,它的属性不能比接口描述的多。

这里重点是直接赋值,如果像例子中,先将对象字面量赋值给变量,再通过变量传参,这样间接的方法可以绕过额外的检查。

4.5 可索引类型

可索引类型包括字符串索引类型与数字索引类型。

4.5.1 字符串索引类型

字符串索引类型具有字符串索引签名。

4.5.2 数字索引类型

数字索引类型具有数字索引签名

4.5.3 混合索引签名

属性和索引签名可以形成混合索引签名,但是属性需要和索引签名类型匹配。

另外,TS 允许同时使用上述两种签名,但是数字索引返回值的类型,它必须是字符串索引返回值类型的子类型。

因为对于 JS 来说,当使用数字索引时,会将它转换成字符串进行索引。所以它们需要保持一致。

上述代码中,ThreeD 是 TwoD 的子类型,所以接口 PointA 正确。

4.5.4 只读索引签名

可以将索引签名设置为只读,只能在数组初始化时定义其值,创建后不能进行修改。

4.6 函数类型

函数类型具有调用签名。

如上述代码所示,调用签名包括参数列表和返回值类型。

对于函数类型来说,它校验的值当然是函数 ——

如上述代码所示,函数的参数名可以与签名的参数名不同。关键是对应位置的参数类型需要相同。

4.7 类类型

这里的概念有些复杂,如果有良好的 JS 基础,会较易理解。

类的关键字是 Class,由 ES6 开始引入,并逐步完善。本质上 Class 属于语法糖,是基于 prototype 原型链实现的。

而无论是 ES5 或 ES6,属性 age 是在创建的实例上,而方法 getAge() 是在实例的原型链上。

而类本身,它是不存在 age 属性 和 getAge() 方法的。

当然,我们也可以给类本身定义属性和方法。 但给类本身定义的属性和方法并不能通过实例直接访问。

所以,类与实例的属性和方法是割裂的。

TS 将描述类的属性和方法部分称为类的静态部分类型,将描述实例的属性和方法部分称为类的实例部分类型。

在上述代码中,使用关键字 implements 描述类实现了接口。更准确的是:描述 类的实例部分 实现了接口。

实现该接口的类的实例,它是具有 age 属性,getAge() 方法。而类本身(即类的静态部分)具有何种属性与方法,上述代码没有进行定义。

所以,这里所说的类类型,实际上是类(实例的)类型。

关于如何定义类的静态部分的类型,在后续会详细介绍。

4.8 接口继承

接口的可以使用关键字 extends 定义继承。一个接口可以继承多个接口。

4.9 混合类型

一个对象可能混合多种类型。

例如定义一个带版本号的函数——

值得注意,上述使用类型断言,将函数断言为 Fn,即使 fn 在创建时并不存在 version 属性。

4.10 接口继承类

当接口继承类类型时候,表现在继承类的成员和结构,但不包括其实现。

接口继承类的一个场景是,定义一个子类的类类型。

结语

由于文章篇幅问题,全文拆分成上下两篇发布。

本篇主要介绍了 TS 的基本类型,引用类型、类型断言、接口等知识点,了解上述的知识点可以阅读部分 TS 代码。

下篇涉及函数、类、泛型等稍微复杂的知识点。

一文学会 TypeScript 的 82% 常用知识点(上)的更多相关文章

  1. 一文学会 TypeScript 的 82% 常用知识点(下)

    一文学会 TypeScript 的 82% 常用知识点(下) 前端专栏 2019-11-23 18:39:08     都已经 9021 年了,TypeScript(以下简称 TS)作为前端工程师不得 ...

  2. DB2_SQL_常用知识点&实践

    DB2_SQL_常用知识点&实践 一.删除表中的数据(delete或truncate) 1 truncate table T_USER immediate; 说明:Truncate是一个能够快 ...

  3. JAVA常用知识点及面试题总结

    1. String.StringBuffer.StringBuilder三者区别? (1)三者在执行速率上的比较: String<StringBuffer<StringBuilder 原因 ...

  4. HTML常用知识点代码演示

    1 HTML部分常用知识点 <!-- 版本声明 --> <!DOCTYPE html> <!-- 唯一根元素 --> <html> <!-- 对网 ...

  5. Java 常用知识点

    Java 常用知识点 1.日期格式化 SimpleDateFormat Date date=new Date(System.currentTimeMillis()) ; SimpleDateForma ...

  6. Less常用知识点

    上篇文章介绍了如何安装Less,我们将所有东西都写在.less里面,最后通过命令将.less转换成.css文件,就可以放入到项目里用了.今天了解一些less常用知识点. 1.变量:声明两个变量,一个是 ...

  7. BIOS备忘录之EC常用知识点

    BIOS工程师眼中常用的EC知识点汇总: EC的硬件架构 EC硬件结构上主要分为两部分:Host Domain和EC Domain Host Domain就是通过LPC与CPU通信的部分(LPC部分需 ...

  8. YII2常用知识点总结

    YII2常用知识点总结 (一)总结性语句 (1)经常看看yii源码比如vendor\yiisoft\yii2\web这个目录(很重要)下的文件中的方法(这些文件中的公共方法,大致看了下基本上都可以通过 ...

  9. CSS3常用知识点

    CSS3常用知识点 1 css3选择器 1.1 属性选择器 /* E[attr~=val] 表示的一个单独的属性值 这个属性值是以空格分隔的*/ .attr2 a[class~="kawa& ...

随机推荐

  1. MTK Recovery 模式横屏修改(适用于6.0 + 8.1)

    修改前 修改后 6.0 Recovery 模式横屏修改方法 修改相关文件 bootable\recovery\minui\Android.mk bootable\recovery\minui\mt_g ...

  2. SpringCloud之Zuul:服务网关

    Zuul在Web项目中的使用见上文<SpringBoot中使用Zuul>,下面例子为Zuul在Spring Cloud的使用. 开发工具:IntelliJ IDEA 2019.2.3 一. ...

  3. 使用“npm init”初始化项目

    使用npm init初始化项目 为什么要使用npm init初始化项目 在node开发中使用npm init会生成一个pakeage.json文件,这个文件主要是用来记录这个项目的详细信息的,它会将我 ...

  4. 使用C#面向对象实现简易计算器(简单工厂模式)

    操作流程: 1. 新建Operation类 2. 新建OperationAdd类,并继承Operation类 3. 新建OperationSub类,并继承Operation类 4. 新建Operati ...

  5. 西北师大-2108Java】第十三次作业成绩汇总

    [西北师大-2108Java]第十三次作业成绩汇总 作业题目 面向对象程序设计(JAVA) 第15周学习指导及要求 实验目的与要求 (1)掌握菜单组件用途及常用API: (2)掌握对话框组件用途及常用 ...

  6. hibernate-positional-parameter-does-not-exist-1-in-query

    经过bug的排查,问题出在,scsj字段的赋值上; 通过字符串在数据库端生成即可:

  7. Linux中fuser命令用法详解

    描述: fuser可以显示出当前哪个程序在使用磁盘上的某个文件.挂载点.甚至网络端口,并给出程序进程的详细信息. fuser显示使用指定文件或者文件系统的进程ID. 默认情况下每个文件名后面跟一个字母 ...

  8. kaldi使用thchs30数据进行训练并执行识别操作

    操作系统 : Ubutu18.04_x64 gcc版本 :7.4.0 数据准备及训练 数据地址: http://www.openslr.org/18/ 在 egs/thchs30/s5 建立 thch ...

  9. PalletOne调色板Token PTN跨链转网的技术原理

    之前一直在忙于通用跨链公链PalletOne的研发,没有怎么做技术分享的博客,最近PalletOne主网上线也有几个月的时间了,即将进行PTN(PalletOne上面的主Token)从ERC20到主网 ...

  10. ASP.NET Server对象

    Server.HtmlEncode() 执行文本代码Server.HtmlDecode()可以将代码显示 而不是执行它 但是ASP.NET会认为恶意 我们可以将aspx代码开头添加validateRe ...