TypeScript 入门指南
TypeScript 入门指南
# TypeScript 简介
# 什么是 TypeScript
一个 JavaScript 超集,包含类型系统,以及其他一些功能。
随着 Promise、Generators 等 API 进入 JS 标准,
TS 和 JS 在这些 API 方面的差别在变小,
但 TS 还有一些独有特性,这些特性才是和 JS 的主要区别:
- 类型系统、type-checking
- 类型(自动)推导、auto-completion
# 为什么要用 TypeScript
- 提升代码健壮性
- 面向接口编程(代码自解释,并行开发)
- 静态检查可以提高开发效率
- 减少开发时(人工推导带来的)认知负荷
# 学习 TypeScript
# 概览
- 耗时:从入门到熟悉需要大约 20~40 小时(个人估计)
- 难点:
- 理解 JS 中没有的 TS 特性
- 训练 TS 的高级用法(泛型、交集、条件等)
- 工具:
# 学习路线
- 前置学习
- JavaScript 学习指南
- 理解编程理念
- 静态类型
- Object Oriented Programming
- Functional Programming
- 学习 TypeScript
- (学习 JavaScript)
- 学习和使用 TypeScript 常用特性
- 学习泛型和类型推导——TS 最难的部分之一
- 尝试将以前写的 JS 代码转换成 TS 版本
- 了解 @types (DefinitelyTyped (opens new window))
- 实战
- 写业务时逐步使用 TS (包括业务代码和 npm 包)
- package 开发打包和声明文件
- 进阶
- 学习 TS 的高级用法
- 阅读一些用库的 TS 相关源码(比如 redux (opens new window))
- 迷思
- 如何将 Object.keys 转换成 enum
- 如何把数组转换成字面量类型
- 如何给复杂的处理函数写类型
- 如何写一个类型表示排除 undefined 的 any
# 资料
# 概览
- 编程漫谈
- 生态
- TS
# 自学教材
- 快速入门
- TypeScript - The Basics (opens new window):12 分钟,历史背景、基本使用、语法简介
- VS Code - IntelliSense (opens new window):前 3 分钟,TS 在 VS Code 的自动完成中起到的作用
- Working with TypeScript in Visual Studio Code (opens new window):10 分钟,在 VS Code 中的使用 TS
- TypeScript - Learn X in Y minutes (opens new window):语法速查表
- 社区文档
- 官方文档(及汉化)
- Documentation - TypeScript (opens new window):官方文档(最新)
- Do's and Don'ts (opens new window):一些最佳实践贴士
- TypeScript-Handbook (opens new window):社区汉化版(尽量保持官方同步)
- Documentation - TypeScript (opens new window):官方文档(最新)
- 在线调试(TS 检查、编译到 JS)
# 进阶/实战
- TS 语言
- 视频
- Fun Times with Advanced TypeScript (opens new window):25 分钟,包含很多 TS 进阶用法(2018 年)
- 深入理解 TypeScript
- Effective TypeScript
- 文章
- Advanced Types (opens new window):官方文档中的「高级类型」章节
- TypeScript Evolution (opens new window):TS 语言特性,系列文章
- TS 进阶概念解析
- 视频
- 开发
# TypeScript 知识体系
# 如何运行 TypeScript
- 命令行命令
tsc
,官方编译器- 安装
npm install -g typescript
- 安装
ts-node
,TS + Node- 安装
npm install -g ts-node
- 安装
parcel
, 自动检测运行- 安装
npm install -g parcel
- 安装
- TS 运行配置
- 工程化
- 工具
- types-checker (opens new window):自动安装 @types
- DefinitelyTyped (opens new window):@types 官网
- ESLint
- Getting Started with ESLint (opens new window):ESLint 官方教程
- @typescript-eslint/parser (opens new window):ESLint 的 TS 插件
- 打包插件
- 工具
# TypeScript 主要概念
- TS 类型系统
type
类型别名、interface
接口- 变量声明/使用 (opens new window)
- 基础类型 (opens new window)
- JS 基本类型
number
、string
、boolean
、undefined
、null
Array
、元组 Tuple (opens new window) (严格的、退化的数组)any
任意类型、never
永不、void
空值(一般用于函数返回undefined
)unknown
(opens new window)- 枚举 (opens new window)
Enums
- JS 基本类型
- 函数 (opens new window)
- 函数的多种定义方式
this
this 参数 (opens new window)- Overloads 重载 (opens new window)
- 接口 (opens new window)
interface
?
Optional Properties (opens new window)readonly
Readonly properties (opens new window)- Indexable Types (opens new window) 可索引类型
{ [x: string]: number }
implements
、extends
- Hybrid Types (opens new window) 混合类型,JS 中允许的 函数 + 对象字段
- 类 (opens new window)
class
extends
、implements
、abstract
public
/private
/protected
,简写法(constructor 参数)readonly
get
/set
static
- 泛型 (opens new window) Generics
- 装饰器 (opens new window) Decorators
- TS 类型操作
- 声明合并 (opens new window)
- 高级类型 (opens new window)
|
Union 联合类型、&
Intersection 交叉类型- 类型收缩(Type Narrowing)(推断)
- 控制流分析(Control Flow Based Type Analysis (opens new window))
- 类型保护(Type Guard (opens new window))
as
、in
、is
、typeof
、instanceof
- 可辨识联合(Discriminated Unions (opens new window))
- 字面量类型(Literal Types)(类似枚举的联合类型)
- 索引类型 Index types (opens new window)、映射类型 Mapped types (opens new window)
- 条件类型(Conditional Types (opens new window))
T extends U ? X : Y
infer
- Utility Types 工具类型 (opens new window)
Partial<T>
Readonly<T>
Record<K,T>
Pick<T,K>
Omit<T,K>
Exclude<T,U>
Extract<T,U>
NonNullable<T>
Parameters<T>
ConstructorParameters<T>
ReturnType<T>
InstanceType<T>
Required<T>
ThisParameterType
OmitThisParameter
ThisType<T>
# TypeScript 典型代码
# TypeScript 基本语法
Check TypeScript - Learn X in Y minutes (opens new window)
// ts-node
// * -------------------------------- 基本
// * ---------------- 基本类型
let isDone: boolean = false;
let lines: number = 42;
let lastName: string = 'Anders';
type MyList = number[];
let list: MyList = [1, 2, 3];
// * ---------------- 函数的几种声明方式
let square = (n: number): number => n * n;
let square2: (n: number) => number = (n) => n * n;
type Sq = (n: number) => number;
let square3: Sq = (n) => n * n;
interface Sq4 {
(n: number): number;
}
let square4: Sq4 = (n) => n * n;
// * ---------------- 枚举
enum Color {
Red = 'Red',
Green = 'Green',
Blue = 'Blue',
}
// * ---------------- 接口、类
interface CarInterface {
model: string;
radio?;
getYear(): any;
}
class Car implements CarInterface {
constructor(
readonly model,
private engine,
public radio?,
) {} // 简写法
static Manufacturer: string = 'BMW';
getYear() {}
}
// * ---------------- 泛型
class Observable<T> {
constructor(public value: T) {}
}
let myOb: Observable<number> = new Observable(2);
// * -------------------------------- 示例
// * ---------------- 接口、对象
interface MyDict {
type: string;
[name: string]: string; // 可索引
}
const dict: MyDict = {
type: 'a dict',
num: 233, // Error!
word: 'hello', // Valid
};
// * ---------------- 递归的声明
type NumVal = 1 | 2 | 3 | NumVal[];
const nestArr: NumVal = [1, 2, 3, [1, 2, [3]]];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# TypeScript 实用代码
# 联合转交集
type UnionToIntersection<U> = (
U extends any ? (k: U) => void : never
) extends (k: infer I) => void
? I
: never;
2
3
4
5
# 复杂的类型声明
infer - 深入理解 TypeScript (opens new window)
通过编写泛型和类型推断,能够拥有更准确的类型,
能保证业务代码拥有更充分的类型提示,提升代码整体质量。
type MapEveryToPromise<T extends object> = {
[K in keyof T]: T[K] extends infer P ? Promise<P> : never;
};
const dataPool = {
key1: 1,
key2: 'hello',
// ...
};
const advanceDataPool: MapEveryToPromise<typeof dataPool> =
{
key1: Promise.resolve(1),
key2: Promise.resolve('hello'),
// ...
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# TypeScript 相关
# 泛型中的命名习惯
很多代码中使用泛型,一般只使用一个大写字母,
这些实际相当于助记符,是缩写。
T
(for Type)E
(for Element)K
(for Key)V
(for Value)
U
没找到出处…
推测是T
的后一位字母,就像i, j, k
一样…
也可能是指 Union
其他根据具体上下文可以同样推测:
S
StateA
Action
# 从 JS 迁移到 TS
Migrating from JavaScript (opens new window)
- 注意!
- 不要一边迁移一边修改代码逻辑
- 不要在低测试覆盖率时迁移
- 初期无需写太严谨的类型(为了开发效率)
- 别忘记写 Type 的测试
- 不要急着上线
- 步骤
- 第一阶段
- 确保测试全部通过
- 把
.js
文件重命名成.ts
- 修复类型检查错误或 TS 编译器报错
- 别改代码逻辑
- 确保测试全部通过
- 第二阶段
- 确保测试全部通过
- 禁止隐式
any
({"noImplicitAny": true }
) - 尽量明确类型
- 安装依赖的
@types
(DefinitelyTyped (opens new window)) - 实在不行用显式的
any
- 安装依赖的
- 确保测试全部通过
- 第三阶段
- 逐步升级,小步 commit
- 打开全部的
strict
选项 (Compiler Options (opens new window)) - 将显式
any
替换成具体类型 - 尽力避免不安全类型声明
- 第一阶段
# TypeScript 和 Flow
Flow (opens new window) 是另一个 JS + type 超集,来自 Facebook。
TypeScript 来自微软,在特性上更丰富。
现在 TypeScript 领先 Flow,
几乎成为了新的 JS 开发标准了(尤其是大型工程)。
# TypeScript 是如何工作/运行的
不严谨但简单的理解:
- 发布和执行前编译,完全退化成合法 JS
- 类型系统全部丢弃
- 无法丢弃的特性会被转义(比如 enum => Object)
可以尝试 Babel 在线编译 (opens new window) 来理解
TypeScript 编译原理 - 深入理解 TypeScript (opens new window)
# TypeScript 是如何基于 JavaScript 被开发出来的
这个问题需要扎实的 CS 基础作为铺垫…
如何看懂 typescript 核心源码,并可以参照 typescript 写一个类似的项目? (opens new window)
# TypeScript 有哪些不足
目前不支持高阶泛型
Allow classes to be parametric in other parametric classes (opens new window)
导致让这个 demo typescript-generic-problem (opens new window)
中的全部代码都拥有准确的类型是一件很困难的事情,
只能修改业务代码,或手动进行类型声明来妥协。