@TOC
什么情况下可以类型断言?
- 要使得A类能够被断言为B类,只需要 A兼容B 或 B兼容A 即可
- 联合类型可以被断言为其中一个类型
- 父类可以断言为子类 子类也可以断言为父类
- any类型可以断言为任意类型 任意类型都可以断言为any类型
举例
当我们想要调用swim方法且不确定类型时, 将类型断言成Fish 那么就不会报错
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function swim(animal: Cat|Fish){
// return animal.swim() // error TS2339: Property 'swim' does not exist on type 'Cat | Fish'
return (animal as Fish).swim()
}
const Hanly: Fish = {
name: 'Tom',
swim(): void{
console.log('那只Hanly鱼在游泳')
}
}
swim(Hanly)
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误 原因: 此时的swim返回值已被断言成Fish类型, Typescript编译器信任了这个断言,所以调用swim没有报错 但这里传的参数是Cat类型, 而Cat类中没有swim方法 故而运行报错
const Tom: Cat = {
name: 'Tom',
run(): void{
console.log('那只Tom猫在奔跑')
}
}
swim(Tom); // 这里编译不会报错 运行会报错
将父类断言为更加具体的子类
class ApiError extends Error{
code:number = 1;
}
class OtherError extends Error{
statusCode:number = 2;
}
function isApi(error: Error): boolean{
// error.code = 2; //由于父类 Error 中没有 code 属性,故直接获取 error.code 会报错
if(typeof (error as ApiError).code === 'number'){
return true
}else{
return false
}
}
子类断言为父类
class Person {
name:string;
age:number;
}
class Teacher extends Person {
eat():void{
console.log('在吃饭')
}
}
const tt = new Teacher();
(tt as Person).name = 'tony';
需要注意的是
当我们引用一个在此类型上不存在的属性或方法时,就会报错,这时我们可以
function fn(val: string | number): number {
if ((val as string).length) {
return (val as string).length
} else {
return val.toString().length
}
}
fn(1)
fn("1")
因为window下没有foo属性 所以直接给window加foo属性会编译出错
window.foo = 1; // 编译报错
// 需要使用类型断言 将window临时断言成any类型
(window as any).foo = 1
双重断言
即打破 (要使得 A类 能够被断言为 B类,只需要 A 兼容 B 或 B 兼容 A 即可) 的规则,使任何类型可被断言为任何另一个类型。若使用了这种双重断言,那么十有八九是非常错误的,它很可能会导致运行时错误。除非迫不得已,千万别用双重断言
class A {
name: string = 'zy';
}
class B {
age: number = 18;
}
function assertAny(a: A): void {
const age = (a as any as B).age;
console.log(age)
}
assertAny({ name: 'tony' })
感谢阅读,如有不当欢迎指点。