导图社区 TypeScript
这是一篇关于TypeScript的思维导图,包括:工具、文件后缀、类型、泛型、符号和关键字、疑问、类、模块和声明文件。
编辑于2022-09-05 11:38:51 北京市TypeScript
工具
npm包
全局安装typescript
使用:
tsc index.ts
会在同级目录生成同名文件文件index.js,里面是编译后的代码
tsc --watch index.ts
会起一个服务,实时编译ts的内容,输出到index.js中
全局安装ts-node
使用:
ts-node index.ts
不生成编译后的js文件,而是直接运行index.ts中的内容
理解:
就像node是js的运行平台一样,在命令行直接使用node index.js可以直接运行js代码。ts-node是ts的运行平台,执行ts-node index.ts ,可以直接运行ts代码
vscode插件
在线运行平台
检查某个包是否支持TS
https://www.typescriptlang.org/dt/search?search=
支持ts的一般会有一个@types/xxx,里面是类型声明文件
文件后缀
.ts
.tsx
用在react的jsx语法里
.d.ts
为了定义(define)类型使用的
在编译的时候生成或者自己写
类型
布尔类型(boolean)
const flag: boolean = true;
Number 类型
const flag: number = 1;
String 类型
const flag: string = "hello";
数组类型(array)
const flag1: number[] = [1, 2, 3];
方式一: a类型[]
a类型是数组元素的类型
const flag2: Array<number> = [1, 2, 3];
方式二:Array[b类型]
b类型是数组元素的类型
元组类型(tuple)
元组( Tuple )表示一个已知数量和类型的数组 ,各个元素的类型,不必要完全的相同,是一种特殊的数组,
const flag: [string, number] = ["hello", 1];
使用场景
react Hooks
const [state, setState] = useState();
Symbol
我们在使用 Symbol 的时候,需要在 tsconfig.json 的 libs 字段加上ES2015
任意类型(any)
TypeScript 允许我们对 any 类型的值执行任何操作 而无需事先执行任何形式的检查
null 和 undefined
let u: undefined = undefined;
let n: null = null;
Unknown 类型
和any类型的区别
unknown和 any 的主要区别是 unknown 类型会更加严格 在对 unknown 类型的值执行大多数操作之前 我们必须进行某种形式的检查 而在对 any 类型的值执行操作之前 我们不必进行任何检查
所有类型都可以被归为unknown 但unknown类型只能被赋值给 any 类型和 unknown 类型本身 而 any 啥都能分配和被分配
void 类型
void表示没有任何类型 当一个函数没有返回值时 TS 会认为它的返回值是void类型
never 类型
never 一般表示用户无法达到的类型
使用场景
例如never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型
never 和 void 的区别 void 可以被赋值为 null 和 undefined 的类型。 never 则是一个不包含值的类型。 拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常
BigInt 大数类型
使用 BigInt 可以安全地存储和操作大整数
我们在使用 BigInt 的时候 必须添加 ESNext 的编译辅助库, 需要在 tsconfig.json 的 libs 字段加上ESNext ,要使用1n需要 "target": "ESNext” ,number 和 BigInt 类型不一样 ,不兼容
Enum 枚举类型
使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错误码等
普通枚举 初始值默认为 0 其余的成员会会按顺序自动增长 可以理解为数组下标
字符串枚举 每个都需要声明
常量枚举 它是使用 const 关键字修饰的枚举,常量枚举与普通枚举的区别是,整个枚举会在编译阶段被删除 我们可以看下编译之后的效果
字面量类型
在 TypeScript 中,字面量不仅可以表示值,还可以表示类型,即所谓的字面量类型。 目前,TypeScript 支持 3 种字面量类型:字符串字面量类型、数字字面量类型、布尔字面量类型,对应的字符串字面量、数字字面量、布尔字面量分别拥有与其值一样的字面量类型
变量必须等于字面量
object, Object 和 {} 类型
object 类型用于表示非原始类型
大 Object 代表所有拥有 toString、hasOwnProperty 方法的类型 所以所有原始类型、非原始类型都可以赋给 Object(严格模式下 null 和 undefined 不可以)
{} 空对象类型和大 Object 一样 也是表示原始类型和非原始类型的集合
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
特征:
使用大写字母来表示未知类型
例子:
我们预先不知道会传入什么类型 但是我们希望不管我们传入什么类型 我们的返回的数组的指里面的类型应该和参数保持一致 那么这时候 泛型就登场了
我们可以使用<>的写法 然后再面传入一个变量 T 用来表示后续函数需要用到的类型 当我们真正去调用函数的时候再传入 T 的类型就可以解决很多预先无法确定类型相关的问题
使用:
多个类型参数
如果我们需要有多个未知的类型占位 那么我们可以定义任何的字母来表示不同的类型参数
泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法,这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束
例子:
使用泛型约束:
注意:我们在泛型里面使用extends关键字代表的是泛型约束 需要和类的继承区分开
也就是用extends约束传入的T必须有length属性才行
泛型接口
定义接口的时候也可以指定泛型
泛型类
泛型类型别名
泛型参数的默认类型
我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用
符号和关键字
冒号:
跟在变量后面,冒号后面是给变量指定的类型。“变量:”
中竖线|
在联合类型中使用
as
类型断言
let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;
尖括号<>
类型断言
泛型
<T = string>
指定泛型的默认类型
感叹号!
非空断言
和&
交叉类型
typeof
类型保护
typeof 关键词除了做类型保护 还可以从实现推出类型
这个例子就是使用 typeof 获取一个变量的类型
instanceof
类型保护
in
类型保护
type is xxx
自定义类型保护
type
类型别名:自定义类型
interface
接口
readonly
只读属性
implements
行为的抽象
propName
接口中任意类型的属性名
extends
接口的继承
泛型约束
keyof
可以用来取得一个对象接口的所有 key 值
[]
使用 [] 操作符可以进行索引访问
infer
在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。
内置工具类型
Exclude<T,U>
从 T 可分配给的类型中排除 U
Extract<T,U>
从 T 可分配给的类型中提取 U
Pick<T,K>
Pick 能够帮助我们从传入的属性中摘取某些返回
Record<K,T>
构造一个类型,该类型具有一组属性 K,每个属性的类型为 T。可用于将一个类型的属性映射为另一个类型。Record 后面的泛型就是对象键和值的类型。
K 对应对应的 key,T 对应对象的 value,返回的就是一个声明好的对象 但是 K 对应的泛型约束是keyof any 也就意味着只能传入 string|number|symbol
Omit<K,T>
基于已经声明的类型进行属性剔除获得新类型
NonNullable
从 T 中排除 null 和 undefined
ReturnType
Parameters
该工具类型主要是获取函数类型的参数类型
Partial Partial
可以将传入的属性由非可选变为可选
Required
可以将传入的属性中的可选项变为必选项,这里用了 -? 修饰符来实现。
Readonly
通过为传入的属性每一项都加上 readonly 修饰符来实现。
@xxx
装饰器
疑问
ts和tsc的区别是什么
元祖类型的使用场景
null和undefined可以赋值给哪些类型
类
模块和声明文件
在默认情况下,当你开始在一个新的 TypeScript 文件中写下代码时,它处于全局命名空间中
使用全局变量空间是危险的,因为它会与文件内的代码命名冲突,推荐使用文件模块
文件模块
文件模块也被称为外部模块。如果在你的 TypeScript 文件的根级别位置含有 import 或者 export,那么它会在这个文件中创建一个本地的作用域
模块是 TS 中外部模块的简称,侧重于代码和复用
模块在其自身的作用域里执行,而不是在全局作用域里
声明文件
文件命名规范为*.d.ts
我们可以把类型声明放在一个单独的类型声明文件中
查看类型声明文件有助于了解库的使用方式
第三方声明文件
@types 是一个约定的前缀,所有的第三方声明的类型库都会带有这样的前缀
可以安装使用第三方的声明文件
查找声明文件
如果是手动写的声明文件,那么需要满足以下条件之一,才能被正确的识别
给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址
在项目根目录下,编写一个 index.d.ts 文件
针对入口文件(package.json 中的 main 字段指定的入口文件),编写一个同名不同后缀的 .d.ts 文件
查找过程如下:
1.先找 myLib.d.ts
2.没有就再找 index.d.ts
3.还没有再找 lib/index.d.js
4.还找不到就认为没有类型声明了
TypeScript 编译器是如何工作的
TypeScript 文本首先会被解析为 token 流。这个过程比较简单,就是单纯地按照分隔符去分割文本即可
接着 token 流会被转换为 AST,也就是抽象语法树。
binder 则根据 AST 信息生成 Symbol(TypeScript 中的一个数据结构
当我们需要类型检查的时候, checker 会根据前面生成的 AST 和 symbols 生成类型检查结果。
当我们需要生成 JS 文件的时候,emitter 同样会根据前面生成的 AST 和 symbols 生成 JS 文件
装饰器
装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为
分类
类装饰器
属性装饰器
方法装饰器
参数装饰器
写法
普通装饰器
装饰器工厂
接口
是什么
接口既可以在面向对象编程中表示为行为的抽象,也可以用来描述对象的形状
怎么用
我们用 interface 关键字来定义接口 在接口中可以用分号或者逗号分割每一项,也可以什么都不加
特征
描述对象的形状
行为的抽象
接口可以在面向对象编程中表示为行为的抽象
定义任意属性
如果我们在定义接口的时候无法预先知道有哪些属性的时候,可以使用[propName:string]:any,定义任意属性名也不限制属性数量
定义了propName是string类型,即任意属性名只要是string类型就行
可以定义不止一个属性
比如这个例子定义了age,school,home等多个属性
接口的继承
使用extends字段
函数类型接口
这么写有啥意义么?我把:discount去掉不也一样么
构造函数的类型接口
用法一般出现在 当我们需要把一个类作为参数的时候 我们需要对传入的类的构造函数类型进行约束 所以需要使用 new 关键字代表是类的构造函数类型 用以和普通函数进行区分
接口和类型别名的区别
实际上,在大多数的情况下使用接口类型和类型别名的效果等价,但是在某些特定的场景下这两者还是存在很大区别。
特定场景的区别:
基础数据类型
与接口不同,类型别名还可以用于其他类型,如基本类型(原始值)、联合类型、元组
重复定义
接口可以定义多次 会被自动合并为单个接口 类型别名不可以重复定义
扩展方式不同
接口的扩展就是继承,通过 extends 来实现。类型别名的扩展就是交叉类型,通过 & 来实现。
函数
函数的定义
可以指定参数的类型、返回值的类型
函数表达式
定义函数类型:及自定义一个类型来设置函数的参数和返回值类型
可选参数
在 TS 中函数的形参和实参必须一样,不一样就要配置可选参数,而且必须是最后一个参数
默认参数
剩余参数
函数重载
是什么
函数(方法)重载:函数名相同,但参数数量或类型不同,从而创建多个方法的一种能力
在 TypeScript 中,表现为给同一个函数提供多个函数类型定义
注意:函数重载真正执行的是同名函数最后定义的函数体 ,在最后一个函数体之前的全都属于函数类型定义, 不能写具体的函数实现方法 只能定义类型
特征
类型推论
指编程语言中能够自动推导出值的类型的能力。 定义时未赋值就会推论成 any 类型 如果定义的时候就赋值就能利用到类型推论
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种 未赋值时联合类型上只能访问两个类型共有的属性和方法
类型断言
语法
值 as 类型
<类型>值
不能在tsx 语法中使用
有时候你会遇到这样的情况,你会比 TypeScript 更了解某个值的详细信息
通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。其实就是你需要手动告诉 ts 就按照你断言的那个类型通过编译(这一招很关键 有时候可以帮助你解决很多编译报错)
以上两种方式虽然没有任何区别,但是尖括号格式会与 react 中 JSX 产生语法冲突,因此我们更推荐使用 as 语法
非空断言
用于断言操作对象是非 null 和非 undefined 类型。在上下文中当类型检查器无法断定类型时 ,可以使用后缀表达式操作符 !
类型别名
类型别名用来给一个类型起个新名字
交叉类型
交叉类型是将多个类型合并为一个类型。通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
类型保护
类型保护就是一些表达式,他们在编译的时候就能通过类型信息确保某个作用域内变量的类型 其主要思想是尝试检测属性、方法或原型,以确定如何处理值
typeof 类型保护
in 关键字
其实就是检测某个属性在值里面是否存在
instanceof 类型保护
自定义类型保护
下面的例子 value is object就会认为如果函数返回 true 那么定义的 value 就是 object 类型