条款19:
- 当ts能推断出相同的类型时,避免写类型标注
- 对于对象,如果已经有定义好的类型可以使用时,应该加入这个类型,编写对象时能够快速编写。同时也可避免对象类型在定义对象时发现,而不是使用时。
- 函数声明类型应该使用显式标注
条款20: 不同类型使用不同的变量
一个变量的类型应该在声明的时候确定并且不再改变
// bad
let id = 0
// do something
id = 'hh'
function getStr(param: number | string) {
}
getStr(id)
// great
const id = 0
const str = 'hh'
getStr(str)
条款21: 理解类型推断
- 对于const声明的简单对象,ts推断的类型是收窄的
const t = 't' // t的类型是't'
let l = 'l' // l的类型是string
function Fn(params: 't') {}
Fn(t) // right
Fn(l) //wrong, string cann't assign to 't'
- 对于对象,ts推断的类型是稍微宽松的
const a = {
name: 'kk'
}
// type is not Record<string, string>
// type is Record<'name', string>
所以当我们希望ts能推断一个收窄的类型时,可以使用as const(收窄类型为常量)。这同时也相当于为name属性加上了readonly声明
当采用这种写法时,意味着整个对象(不管任何层级)都是只读的。之前readonly只能起到浅层限制的作用
条款22:理解类型收缩
- ts通过代码逻辑(if、in、instanceof、Array.isArray等),推断出类型收缩
- 通过标记联合收缩类型
- 通过自定义类型保护收缩类型
// param is Student if isStudent return true
function isStudent(param: Student | Teacher): param is Student {
return 'name' in param
};
条款23:一次性构建对象,避免多次赋值导致的类型不合法
- 根据条件添加多个属性,并且推断类型
const first = { name: 'first'}
declare let hasSecond: boolean;
const third = { ...first, ...(hasSecond ? { age: 'age'} : {})}
third.age
// 书中推到third的类型为{ name: string} | { name: string, age: string}
// 实际上在4.X版本的ts playground, 推导的类型为 { name: string, age?: string},访问third.age不会报错
条款24:使用别名时保持一致
注意调用函数可能会使某一个收缩的变量类型产生变化
条款25: 使用async await
条款26:类型推断中怎么使用上下文
- const声明获得上下文
- 定义对象时的上下文
const person: Person = {
//...
}
- 函数内的上下文
function fn(cb: (a: number, b: number) => void) {
cb(Math.random(), Math.random())
}
fn((a,b) => a + b) // 根据fn定义,可以推断a,b都是number类型
条款27: 使用工具库,在处理复杂对象时加快类型的扭转(因为库中已经处理好类型问题了)