类型断言(*)
类型断言(Type Assertion)可以用来手动指定一个值的类型。
值 as 类型;
或
<类型>值;
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
用途
将一个联合类型断言为其中一个类型
此时可以使用类型断言,将
animal断言成Fish,以此欺骗编译器,避免访问animal.swim时报错的问题interface Cat { name: string; run(): void; } interface Fish { name: string; swim(): void; } function isFish(animal: Cat | Fish) { if (typeof (animal as Fish).swim === "function") { return true; } return false; }但在运行时可能会报错。总之,使用类型断言时一定要格外小心,尽量避免断言后调用方法或引用深层属性,以减少不必要的运行时错误。
将一个父类断言为更具体的子类
interface ApiError extends Error { code: number; } interface HttpError extends Error { statusCode: number; } function isApiError(error: Error) { if (typeof (error as ApiError).code === "number") { return true; } return false; }上面的例子中,声明了函数
isApiError,它用来判断传入的参数是不是ApiError类型,为了实现这样一个函数,它的参数的类型肯定得是比较抽象的父类Error,这样的话这个函数就能接受Error或它的子类作为参数了。但是由于父类
Error中没有code属性,故直接获取error.code会报错,需要使用类型断言获取(error as ApiError).code。将任何一个类型断言为 any
一般用于使用 any 进行临时断言。
(window as any).foo = 1;在
any类型的变量上,访问任何属性都是允许的。需要注意的是,将一个变量断言为
any可以说是解决 TypeScript 中类型问题的最后一个手段。它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用
as any。将 any 断言为一个具体的类型
function getCacheData(key: string): any { return (window as any).cache[key]; } interface Cat { name: string; run(): void; } const tom = getCacheData("tom") as Cat; tom.run();上面的例子中,我们调用完
getCacheData之后,立即将它断言为Cat类型。这样的话明确了tom的类型,后续对tom的访问时就有了代码补全,提高了代码的可维护性。
限制
联合类型可以被断言为其中一个类型
父类可以被断言为子类
任何类型都可以被断言为 any
any 可以被断言为任何类型
要使得
A能够被断言为B,只需要A兼容B或B兼容A即可类型断言并不是任何时候都可以成功,不可滥用:
const fn = (type: any): boolean => { return type as boolean; }; let cb = fn(1); console.log(cb); // 1
双重断言
除非迫不得已,千万别用双重断言。
类型断言 vs 类型转换
所以类型断言不是类型转换,它不会真的影响到变量的类型。
若要进行类型转换,需要直接调用类型转换的方法:
function toBoolean(something: any): boolean {
return Boolean(something);
}
toBoolean(1);
// 返回值为 true
类型断言 vs 类型声明
类型声明是比类型断言更加严格的。
所以为了增加代码的质量,我们最好优先使用类型声明,这也比类型断言的 as 语法更加优雅。
类型断言 vs 泛型
function getCacheData(key: string): any {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData("tom") as Cat;
tom.run();
我们还有第三种方式可以解决这个问题,那就是泛型:
function getCacheData<T>(key: string): T {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData<Cat>("tom");
tom.run();
通过给 getCacheData 函数添加了一个泛型 <T>,我们可以更加规范的实现对 getCacheData 返回值的约束,这也同时去除掉了代码中的 any,是最优的一个解决方案。