typescript 全面进阶指南
2023-06-06 09:49:36 0 举报
AI智能生成
typescript 全面进阶指南
作者其他创作
大纲/内容
体系
类型
目的
为 JavaScript 代码添加类型与类型检查来确保健壮性
内容及其表现
为 JavaScript 中的变量、函数等概念提供了类型的标注,<br>同时内置了一批类型工具,基于这些类型工具我们就能实现更复杂的类型描述,<br>将类型关联起来
语法
目的
提前使用新语法或新特性来简化代码
内容及其表现
比如使用最多的可选链(?.)、空值合并(??)、装饰器等,<br>这些语法都已经或即将成为 ECMAScript Next 的新成员
工程
目的
最终获得可用的 JavaScript 代码
内容极其表现
TypeScript 会在构建时被抹除类型代码与语法的降级。<br>这一能力就是通过 TypeScript Compiler(tsc)实现的。<br>tsc 以及 tsc 配置(TSConfig)是 TypeScript 工程层面的重要部分
通过类型声明的方式,在 TypeScript 中愉快地使用 JavaScript 社区的大量 npm 包
TypeScript 开发环境配置
VS Code 插件
TypeScript Importer
VS Code 内置的 TypeScript 配置
搜索 'typescript Inlay Hints',展示的配置就都是提示相关的了,推荐开启的有这么几个:<br><br>Function Like Return Types,显示推导得到的函数返回值类型;<br>Parameter Names,显示函数入参的名称;<br>Parameter Types,显示函数入参的类型;<br>Variable Types,显示变量的类型。
NPM 开发配置
ts-node
配置
<b>-P,--project</b>:指定你的 tsconfig 文件位置。默认情况下 ts-node 会查找项目下的 tsconfig.json 文件
<b>-T, --transpileOnly</b>:禁用掉执行过程中的类型检查过程,这能让你的文件执行速度更快,且不会被类型报错卡住。<br>这一选项的实质是使用了 TypeScript Compiler API 中的 transpileModule 方法
<b>--swc</b>:在 transpileOnly 的基础上,还会使用 swc 来进行文件的编译,进一步提升执行速度
<b>--emit</b>:如果你不仅是想要执行,还想顺便查看下产物,可以使用这一选项来把编译产物输出到 .ts-node 文件夹下(需要同时与 --compilerHost 选项一同使用)
缺点
ts-node 本身并不支持自动地监听文件变更然后重新执行
ts-node-dev
优势
ts-node-dev 基于 node-dev(你可以理解一个类似 nodemon 的库,提供监听文件重新执行的能力) 与 ts-node 实现,<br>并在重启文件进程时共享同一个 TS 编译进程,避免了每次重启时需要重新实例化编译进程等操作
NodeJs 中的 require 逻辑
类型标注
原始类型
number
string
boolean
undefined
null
symbol
bigint
void
数组类型
使用
元组(Tuple)
同类型数组元素的类型标注
不同类型数组元素的类型标注
可选成员数组元素的类型标注
具名元组-为元组中的元素打上类似属性的标记
具名元组可选元素的修饰符
对象类型
需要特殊的类型标注来描述对象类型-interface
标记一个属性为可选-?
标记属性为只读:readonly
type/interface
interface 用来描述对象、类的结构
类型别名用来将一个函数签名、一组联合类型、一个工具类型等等抽离成一个完整独立的类型
字面量类型
概念
将实际的<b>"值"</b>作为类型
分类
字符串字面量类型
数字字面量类型
布尔字面量类型
对象字面量类型
场景1
总结
单独使用字面量类型比较少见,因为单个字面量类型并没有什么实际意义。<br>它通常和联合类型(即这里的 |)一起使用,表达一组字面量类型
无论是原始类型还是对象类型的字面量类型,它们的本质都是类型而不是值。<br>它们在编译时同样会被擦除,<br>同时也是被存储在内存中的类型空间而非值空间
联合类型
概念
一组类型的可用集合
使用
场景1
枚举
使用
规则
如果你没有声明枚举的值,它会默认使用数字枚举,并且从 0 开始,以 1 递增
如果你只为某一个成员指定了枚举值,那么之前未赋值成员仍然会使用从 0 递增的方式,之后的成员则会开始从枚举值递增
延迟求值的枚举值
延迟求值的成员不能放在最后
同时使用字符串枚举值和数字枚举值
对象与枚举的区别
枚举是双向映射的,即你可以从枚举成员映射到枚举值,也可以从枚举值映射到枚举成员
对象是单向映射的,我们只能从键映射到键值
常量枚举
函数
函数的类型签名<br><br>
概念
描述了函数入参类型与函数返回值类型
使用方式1-直接在函数中进行参数和返回值的类型声明
使用方式2-使用类型别名将函数声明抽离出来
使用方式3-使用 interface 来进行函数声明
如何命名一个函数
函数声明(Function Declaration)
函数表达式(Function Expression)
void 类型
一个没有返回值(即没有调用 return 语句)的函数,其返回类型应当被标记为 void
可选参数
可选参数必须位于必选参数之后
rest参数
使用方式1
使用方式2-使用元组类型进行标注
函数重载签名(Overload Signature)
异步函数、Generator 函数的类型签名
异步函数(即标记为 async 的函数),其返回值必定为一个 Promise 类型,<br>而 Promise 内部包含的类型则通过泛型的形式书写,即 Promise<T>
Class<br>
主要结构
构造函数
属性/方法
访问符(Accessor)
setter 方法不允许进行返回值的类型标注
修饰符
public
此类成员在类、类的实例、子类中都能被访问
private
此类成员仅能在类的内部被访问
protected
此类成员仅能在类与子类中被访问
readonly
静态成员-static
在类的内部静态成员无法通过 this 来访问,需要通过 Foo.staticHandler 这种形式进行访问
继承、实现、抽象类
基类(Base)
派生类(Derived)
内置类型
Top Type
any
概念
表示一个无拘无束的“任意类型”,它能兼容所有类型,也能够被所有类型兼容
本质
any 的本质是类型系统中的顶级类型,即 Top Type
原则
如果是类型不兼容报错导致你使用 any,考虑用类型断言替代
如果是类型太复杂导致你不想全部声明而使用 any,考虑将这一处的类型去断言为你需要的最简类型。<br>如你需要调用 foo.bar.baz(),就可以先将 foo 断言为一个具有 bar 方法的类型
如果你是想表达一个未知类型,更合理的方式是使用 unknown
unknown
一个 unknown 类型的变量可以再次赋值,并且只能赋值给 any 与 unknown 类型的变量
any 放弃了所有的类型检查,而 unknown 并没有<br><br>对 unknown 类型进行属性访问,需要进行类型断言<br>
Bottom Type
never
场景-一个只负责抛出错误的函数
场景2-未标明类型的数组被推导为了 never[] 类型,<br>这种情况仅会在你启用了 strictNullChecks 配置,<br>同时禁用了 noImplicitAny 配置时才会出现。<br><br>解决的办法也很简单,为这个数组声明一个具体类型即可
类型断言
as
案例
双重断言
背景
如果在使用类型断言时,原类型与断言类型之间差异过大<br>TypeScript 会给你一个类型报错<br>此时它会提醒你先断言到 unknown 类型,再断言到预期类型<br><br>这是因为你的断言类型和原类型的差异太大,需要先断言到一个通用的类,即 any / unknown。<br>这一通用类型包含了所有可能的类型,因此断言到它和从它断言到另一个类型差异不大<br>
非空断言---!<br>
类型层级关系
最顶级的类型,any 与 unknown
特殊的 Object ,它也包含了所有的类型,但和 Top Type 比还是差了一层<br>
String、Boolean、Number 这些装箱类型
原始类型与对象类型<br>
字面量类型,即更精确的原始类型与对象类型嘛,需要注意的是 null 和 undefined 并不是字面量类型的子类型
最底层的 never
0 条评论
下一页