我们通常在javascript中通过判断来处理一些逻辑,在typescript中,这种条件语句还有另外一个特性:根据判断逻辑的结果,缩小类型范围(有点类似类型断言),这种特性成为类型保护,出发条件:
- 逻辑条件语句块:if else elseif
- 特定的一些关键字:typeof / instanceof / in ...
typeof
我们知道 typeo f可以返回某个数据的类型,在typescript中if、else代码块中能够把 typeof 识别为类型保护,推断出合理的类型
function fn(a:string | number){
//error 不能保证a就是字符串
// a.substring(1)
//类型断言
(<string> a).substring(1)
//类型保护
if(typeof a === 'string'){
//ok
a.substring(1)
}else{
//ok
a.toFixed(1)
}
}
instanceof
与 typeof 类似的,instanceof也可以被 typescript 识别为类型保护
function fn(a: Date | Array<any>) {
if( a instanceof Array){
a.push(1)
}else{
a.getFullYear()
}
}
in
in 也是如此
interface IA {
x: string,
y: string
}
interface IB {
a: string,
b: string
}
function fn(arg: IA | IB){
if( 'x' in arg){
// ok
arg.x
//error
arg.a
}else{
// ok
arg.b
//error
arg.y
}
}
字面量类型保护
如果类型为字面量类型,那么还可以通过该字面量类型的字面值进行推断
interface IA {
type: 'IA',
x: string,
y: string
}
interface IB {
type: 'IB',
a: string,
b: string
}
function fn(arg: IA | IB){
if(arg.type === 'IA'){
// ok
arg.x
//error
arg.a
}else{
// ok
arg.b
//error
arg.y
}
}
自定义类型保护
有的时候,以上的一些方式并不能满足一些特殊情况,则可以自定义类型保护规则
//data is Element[] | NodeLIst是一种类型谓词,格式为:xx is XX,返回这种类型的函数就可以被保护
function canEach(data: any) : data is Element[] | NodeLIst {
return data.forEach !== undefined;
}
function fn(elements: Element[] | NodeList | Element){
if(canEach(elements)){
elements.forEach(el:Element=>{
el.classList.add('box')
})
}else{
elements.classList.add('box')
}
}