本文记录自己学习 TypeScript 过程中遇到的一些知识点,偏向 Vue3 + TS 企业项目中的实际使用,而不是 TS 官方语法大全。
一、冒号 : 和 as 的区别
这是刚接触 TS 最容易搞混的两个语法。
: —— 声明类型
谁的类型,就跟着谁。
变量
const name: string = 'Tom'表示:
name 是 string。
参数
function sum(a: number, b: number) {}表示:
参数 a、b 都是 number。
返回值
function getName(): string { return 'Tom'}表示:
函数返回 string。
as —— 类型断言
告诉 TS:
我知道它是什么类型,请相信我。
例如:
const data = {} as Record<string, string>并不会修改运行时的数据,只影响 TS 类型检查。
总结
二、Record
这是 TS 最常见的工具类型之一。
Record<KeyType, ValueType>例如:
Record<string, number>等价于:
{ [key: string]: number}表示:
一个对象,key 是字符串,value 是 number。
例如:
{ age: 18, score: 100}如果:
Record<string, User[]>表示:
对象├── key1 -> User[]├── key2 -> User[]└── key3 -> User[]注意:
不是字符串数组。
而是:
key 是 string,value 是数组。
三、& 与 |
| —— 联合类型
表示:
或者
例如:
type Value = string | number可以是:
'abc'也可以:
123& —— 交叉类型
表示:
同时拥有。
例如:
type User = BaseUser & { age: number}等价:
BaseUser+age四、Type Predicate(类型守卫)
项目中经常看到:
(value): value is User例如:
const isUser = (value: unknown): value is User => {}这里:
value is User不是返回 User。
实际上:
返回值仍然是:
boolean但是告诉 TS:
如果返回 true,那么:
value以后就是:
User例如:
if (isUser(data)) { data.name}TS 会自动推断:
data: User五、泛型 < >
很多 Vue API 都有:
ref<User>()computed<User>()reduce<User>()这里:
<>叫:
泛型。
作用:
告诉函数:
它操作的数据类型是什么。
例如:
ref<number>(0)表示:
ref 里面保存 number。
computed<User[]>(() => {})表示:
computed 最终返回 User[]。
reduce<Record<string, User[]>>(...)表示:
reduce 最终累计出来的是:
Record<string, User[]>六、类型声明应该写在哪里?
最容易记的一句话:
谁的类型,就跟着谁。
记住:
变量 → 名字后参数 → 括号里返回值 → 括号后泛型 → 函数后面的 <>七、为什么有时候写返回值,有时候不写?
例如:
const sum = (a:number,b:number)=>{ return a+b}TS 可以自动推断:
number所以可以不写。
但是:
const isUser = (value): value is User => {}必须写。
因为:
TS 推断不了:
返回 true 时 value 是什么类型。
一般原则:
TS 能推断 → 可以不写
TS 推断不了 → 必须写
公共工具函数 → 建议写
八、reduce 的 result 是什么?
很多人会误认为:
(result, item)里面:
result是上一项。
其实不是。
它叫:
累积值(Accumulator)
例如:
const result = arr.reduce((sum, item) => {}, 0)第一次:
sum = 0item = 第一个元素第二次:
sum = 第一次 returnitem = 第二个元素所以:
result 永远是:
上一次 return 的结果。
九、为什么 {} 可以赋值给 Record?
例如:
const result: Record<string, number> = {}这是合法的。
原因:
Record 的意思不是:
必须马上拥有所有 key。
而是:
如果以后添加 key,那么 value 必须符合类型。
例如:
result.age = 18合法。
但是:
result.age = '18'报错。
十、Array.from(new Set())
项目中很常见:
Array.from(new Set(array))作用:
去重。
例如:
[1,2,2,3]变:
[1,2,3]通常搭配:
fields .map(...)组成:
Array.from( new Set( fields.map(...) ))流程:
数组 ↓map 提取 ↓Set 去重 ↓Array.from 转数组十一、看到链式调用时的阅读方式
例如:
fields .map(...) .filter(...) .sort(...)建议不要一口气看。
而是拆成:
fields↓map(提取需要的数据)↓filter(过滤)↓sort(排序)↓最终结果很多复杂代码,拆开后都会简单很多。
十二、学习 TS 的思路
目前自己的体会:
不要死记语法。
看到一个类型声明,先问自己:
它描述的是谁?
例如:
(a: User)描述参数。
(): User描述返回值。
const a: User描述变量。
ref<User>()告诉 ref 保存 User。
只要牢记:
谁的类型,就跟着谁。
绝大部分 TS 写法都能理解。
十三、JS 与 TS 的区别
目前最大的理解:
JavaScript:
代码能运行即可。
TypeScript:
在代码运行之前,提前告诉编译器数据是什么类型,从而减少错误。
TS 并不会改变 JS 的运行逻辑。
它更多是一套:
类型约束 + 类型推断。
所以:
学习 TS,不是在学习新的运行机制。
而是在学习:
如何正确描述数据。