1. 类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。语法值 as 类型。

2. 断言应用

将一个联合类型断言为其中一个类型。

  1. interface Cat {
  2. name: string;
  3. run(): void;
  4. }
  5. interface Fish {
  6. name: string;
  7. swim(): void;
  8. }
  9. function getName(animal: Cat | Fish) {
  10. return animal.name;
  11. }
  12. function isFish(animal: Cat | Fish) {
  13. if (typeof (animal as Fish).swim === 'function') {
  14. return true;
  15. } else {
  16. return false;
  17. }
  18. }
  19. function swim(animal: Cat | Fish) {
  20. //不恰当断言
  21. (animal as Fish).swim();
  22. }
  23. const tom: Cat = {
  24. name: 'Tom', run() {
  25. console.log('run');
  26. }
  27. }
  28. //编译通过,运行出错,Cat无 swim()函数
  29. swim(tom);
  30. //- Uncaught TypeError: animal.swim is not a function`

将父类断言为一个子类。

  1. class ApiError extends Error {
  2. code: number = 0;
  3. }
  4. class HttpError extends Error {
  5. statusCode: number = 200;
  6. }
  7. //断言,通过typeof 来判断类型
  8. function isApiError(error: Error) {
  9. if (typeof (error as ApiError).code === 'number') {
  10. return true;
  11. } else {
  12. return false;
  13. }
  14. }
  15. //通过instanceof 来判断error是否是ApiError的实例
  16. function isApiErrorOther(error: Error) {
  17. if (error instanceof ApiError) {
  18. return true;
  19. } else {
  20. return false;
  21. }
  22. }

在接口使用中,使用断言

  1. interface ApiError extends Error {
  2. code: number;
  3. }
  4. interface HttpError extends Error {
  5. statusCode: number;
  6. }
  7. function isApiErrorLast(error: Error) {
  8. if (typeof (error as ApiError).code === 'number') {
  9. return true;
  10. } else {
  11. return false;
  12. }
  13. }

将任何一个类型断言为**any**

  1. //给window添加一个属性,如果不用断言,这会编译出错
  2. (window as any).foo = 1 ;

在上述示例中,需要注意的是,将一个变量断言为any是解决TypeScript中类型问题的最后一个手段。他极有可能掩盖了真正的类型错误,所以如果不是非常确定的情况下,不建议使用 **as any**
**any**断言为一个具体的类型

  1. function getCacheData(key: string): any {
  2. return (window as any).cache[key];
  3. }
  4. interface Cat{
  5. name: string ;
  6. run():void ;
  7. }
  8. //将any类型断言为具体类型
  9. const t = getCacheData('tom') as Cat ;
  10. t.run() ;

上述示例中,我们调用完getCacheData之后,立即将其断言为Cat类型,这样明确了t的类型,提高了代码的可维护性。
总结:

  • 联合类型可以被断言为其中一个类型
  • 父类可以被断言为子类
  • 任何类型都可以被断言为any
  • any可以被断言为任何特定类型
  • 需要A能够断言为B,只需要A兼容B或者B兼容A即可。

子类父类相互断言

  1. interface Animal {
  2. name: string;
  3. }
  4. interface Cat extends Animal {
  5. run(): void;
  6. sleep(): void;
  7. }
  8. function testAnimal(animal: Animal) {
  9. return animal as Cat;
  10. }
  11. function testCat(cat: Cat) {
  12. return cat as Animal;
  13. }

双重断言

  1. interface Cat {
  2. run():void ;
  3. }
  4. interface Fish{
  5. swim():void ;
  6. }
  7. //双重断言
  8. function testCatOther(cat: Cat){
  9. return cat as any as Fish ;
  10. }

上述示例:如果直接使用cat as Fish肯定会提示错误,因为CatFish相互都不兼容,但若使用双重断言,则可以打破【要使得 A能够被断言为 B,只需要 A兼容 BB 兼容 A 即可】的限制,将任何一个特定类型断言为另外一个任何特定类型。若使用了双重断言,那么大部分情况是错误的,所以尽量避免使用双重断言
类型断言 vs 类型转换
类型断言只会影响TypeScript编译时的类型,类型断言语句在编译结果总会被删除。

  1. function toBoolean(some: any): boolean {
  2. return some as boolean;
  3. }
  4. toBoolean(1) ;
  5. //返回值为1
  6. function toBooleanOther(some: any):boolean{
  7. return Boolean(some) ;
  8. }
  9. toBooleanOther(1) ;
  10. //返回值为true
  1. function getCacheDataOther(key: string): any {
  2. return (window as any).cache[key];
  3. }
  4. interface Cat {
  5. name: string;
  6. run(): void;
  7. }
  8. //将any类型转换为Cat
  9. const c: Cat = getCacheDataOther('tom');
  10. c.run();

上述示例中,通过类型声明的方式,将c声明为Cat,然后将any类型的数据 getCacheData('tom')赋值给Cat类型的c
类型断言 vs 类型转换

  1. interface Animal {
  2. name: string;
  3. }
  4. interface Cat extends Animal {
  5. run(): void;
  6. }
  7. const animal: Animal = {
  8. name: 'tom'
  9. }
  10. //类型转换会编译出错
  11. let a: Cat = animal;
  12. //编译错误
  13. - error TS2741: Property 'run' is missing in type 'Animal' but required in type 'Cat'.

上述示例中,不允许将animal赋值为Cat类型的a,因为AnimalCat的父类,当然不能将父类的实例赋值给子类变量。
类型断言和类型转换的核心区别在于:

  • animal断言为Cat,只需啊哟满足Animal兼容Cat或者Cat兼容Animal即可。
  • animal赋值给a,则需要Cat兼容Animal才行,但是Cat并不兼容Animal
  • 类型声明比类型断言更加严格。

类型断言 vs 泛型

  1. function getCacheDataLast<T>(key:string) :T {
  2. return (window as any).cache[key] ;
  3. }
  4. interface Cat{
  5. name: string ;
  6. run():void ;
  7. }
  8. const s = getCacheDataLast<Cat>('tom') ;
  9. s.run() ;

通过给getCacheDataLast函数添加一个泛型<T>,我们可以更加规范的实现对getCacheDataLast返回值的约束,也同时去掉代码中的any,此方法是最优解决方案。