TypeScript 入门|青训营笔记

128 阅读6分钟

这是我参与「第四届青训营 」笔记创作活动的的第9天

为什么选择 TypeScript

了解一件事物先去了解它发展的历史,历史代表着它产生的含义和意义。

  • 2012-10:微软发布了 TypeScript 第一个版本(0.8)
  • 2014-10: Angular 发布了基于 TypeScript 的2.0版本
  • 2015-04:微软发布了 Visual Studio Code
  • 2016-05:@types/react 发布, TypeScript 可开发 React
  • 2020-09: Vue 发布了3.0版本,官方支持 TypeScript
  • 2021-11: v4.5版本发布

TypeScript (静态类型、弱类型语言) 源于 JavaScript (动态类型、弱类型语言)。

  • 动态类型:执行阶段才去确定类型的匹配(控制台执行)
  • 静态类型:类型匹配会提前进行,编译的时候(像 python 、 Java)
  • 弱类型语言:类型转换(字符串和数字可相加,强类型就不可以)

TypeScript 特点:

  1. 静态类型
    • 可读性增强:基于 TypeScript 语法解析 TSDoc , ide 增强
      • 例如:可以自动生成文档,类型基本上就说明了含义,实现类型相当于在写一个文档
    • 可维护性增强:在编译阶段暴露大部分错误 => 多人合作的大型项目中,获得更好的稳定性和开发效率
      • 例如:语法拼写错误、类型匹配错误
  2. JS 的超集
    • 包含于兼容所有 JS 特性,支持共存
    • 支持渐进式引入与升级

编辑器推荐:

  • Visual Studio Code
  • TypeScript 官网的在线编辑器

基本语法

基本数据类型

image.png

对象类型

image.png

函数类型

image.png 函数特性 —— 重载:允许我们有多个具有相同名称但不同参数列表的函数。
规则:

  • 两个函数有不同的参数类型
  • 两个函数的参数数量不同
  • 两个函数有不同的参数类型顺序

image.png 简化:函数的编写形式有时候对我们来说是比较麻烦,为了更方便的去改变我们编写代码。 image.png 图中简化会报错,报错内容为注释内容。
TypeScript 做了两个步骤:

  1. 定义了一个匿名函数((type, timeStamp) => {...}),将匿名函数赋值给了变量 getDate2 并且约定了 getDate2 类型为 IGetDate 类型;
  2. 匿名函数赋值给了变量 getDate2 ,这时候发生了一次类型匹配,因为我们没有对匿名函数进行函数类型声明, TypeScript 会对它做一次类型推断,然后把匿名函数类型和 IGetDate 类型做匹配。

TypeScript 将匿名函数推断为 (type: "string" | "date", timeStamp: string | undefined) => string | Date , IGetDate 存在 函数(除第三个函数声明)的范围表达小于匿名函数的范围表达,所以报错。
更改方案:

  1. 将前面两个重载注释掉。
  2. 将前两个重载的 type 和返回值类型都改成 any 。

个人觉得还是别简化了,更麻烦也更难理解。

数组类型

image.png

TypeScript 的补充类型

image.png

TypeScript 泛型

泛型:不预先指定具体的类型,而在使用的时候再指定类型,它是一种变量指代。 image.png         图中划红线的方式比较粗暴,也达不到想要的效果(比如:传入一个数字时它应该返回的是数字数组),返回完以后的整个传入参数会造成类型的丢失,因为它被重写成了 any 。
        T 就是我们所说的泛型,然后把 target 给了一个 T ,返回 T 的一个数组, T 在函数的执行过程中才去确定类型(根据传入内容的类型)。
泛型不仅仅可以在函数中使用: image.png

泛型两个比较高级的语法
  • 泛型约束 image.png
  • 泛型的默认类型 image.png

类型别名 & 类型断言

image.png

字符串/数字 字面量

允许指定 字符串/数字 必须的固定值: image.png


高级类型

例子

联合/交叉 类型

image.png 问题:

  1. 右边的类型声明的代码比左边多;
  2. 存在重复元素,例如: author ;
  3. 元素 type 描述不准确,左边只能取值两种 history 和 story ,右边为 string 。
  • 联合类型: IA | IB ;联合类型表示一个值可以是几种类型之一
  • 交叉类型: IA & IB ;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性

image.png

类型保护与类型守卫

image.png

类型保护

image.png reverse 方法只有数组才支持,字符串其实是不支持 reverse 的。
typeof 和 instanceof 是 TypeScript 内置的类型保护,当使用 typeof 时, TypeScript 能自动识别出符合它的一个类型。
typeof 和 instanceof 的区别:
        typeof 的返回值是一个字符串,用来说明变量的数据类型; instanceof 的返回值是布尔值,用于判断一个变量是否属于某个对象的实例。

类型守卫

image.png : arg is IA 是类型谓词,当函数 getIsIA 的返回值为 true 时,输入的参数 arg 一定是 IA 类型。
这样的函数只能返回布尔值。
!!(arg as IA).a 当它存在 a 时断言它一定是 IA 类型。

当两个类型完全没有任何重合点时我们才要去写一个类型守卫。

高级类型

image.png
第一种方式(merge1)比较安全,子集不污染的合并。
第二种方式(merge2)对象结构的方式来进行快速的实现,对象结构的方式有可能造成污染。(不理解)

怎么样为上图函数编写类型
方式一: image.png 方式二:
不知道会传入一个什么样的 Object ,也就是类型定义的时候是不明确的,在使用时才明确。 image.png Record 是高级类型,第一个泛型(string)定义的 Object 中 key 的类型,第二个泛型表示的是 Object 中 value 的类型,所以 Record<string, any> 就是一个 any Object 的简单表达。
Partial 为 TypeScript 内置类型, IPartial 写的是 Partial 具体实现。

函数返回值类型

image.png
入参是函数类型,出参是函数的返回值,函数的返回值应该怎么样定义呢?函数的返回值在定义时是不明确的,在使用时才能确认函数的返回值是什么类型的。 image.png <T extends () => any>() => any 表示函数。
<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any 中,第二个 extends 表示类型推断相当于三元表达式中的“===”。(extends 跟随泛型出现并且出现在类型定义(不是声明)中时,表示类型推断)
ReturnType 为 TypeScript 内置类型, IReturnType 写的是 ReturnType 具体实现。


工程应用

浏览器 Web

  1. 配置 webpack loader 相关配置;
  2. 配置 tsconfig.json 文件;
  3. 允许 webpack 启动/打包;
  4. loader 处理 ts 文件时会进行编译与类型检查。

webpack loader 把 webpack 中不能识别的文件(ts 文件)转化成 webpack 可识别的文件(js 文件), webpack 主要是处理 js 文件的。

相关 loader :

  1. awesome-typescript-loader
  2. babel-loader

NodeJs

image.png

  1. 安装 Node 与 npm ;
  2. 配置 tsconfig.json 文件;
  3. 使用 npm 安装 tsc ;
  4. 使用 tsc 运行编译得到 js 文件。