类型断言与非空断言

什么是类型断言?

类型断言(Type Assertion)是TypeScript中一种告诉编译器"你比它更了解某个值的类型"的方式。它类似于其他语言中的类型转换,但不进行特殊的数据检查或解构。

类型断言的两种语法

TypeScript提供了两种类型断言的语法:

  1. 尖括号语法
typescript 复制代码
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
  1. as语法
typescript 复制代码
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

在React项目中,由于JSX与尖括号语法存在冲突,通常推荐使用as语法。

类型断言的使用场景

  1. 将一个联合类型断言为其中一个类型
typescript 复制代码
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;
}
  1. 将父类断言为更具体的子类
typescript 复制代码
class ApiError extends Error {
  code: number = 0;
}
class HttpError extends Error {
  statusCode: number = 200;
}

function isApiError(error: Error) {
  if (typeof (error as ApiError).code === 'number') {
    return true;
  }
  return false;
}

什么是非空断言?

非空断言(Non-null Assertion)是TypeScript 2.0引入的一个特性,它告诉TypeScript编译器某个值不会是nullundefined

非空断言语法

非空断言使用!后缀表示:

typescript 复制代码
function liveDangerously(x?: number | null) {
  console.log(x!.toFixed()); // 使用!断言x不会是null或undefined
}

非空断言的使用场景

  1. 访问可能为null/undefined的属性或方法
typescript 复制代码
function getLength(text?: string) {
  return text!.length; // 断言text不会是undefined
}
  1. 与可选链操作符结合使用
typescript 复制代码
let user = {
  address?: {
    street?: string
  }
};

const street = user.address!.street; // 断言address存在

类型断言与非空断言的注意事项

  1. 不要滥用断言:断言会绕过TypeScript的类型检查,滥用可能导致运行时错误。

  2. 优先使用类型守卫:在可能的情况下,优先使用类型守卫(type guards)而不是断言:

typescript 复制代码
// 更好的做法
function getLength(text?: string) {
  if (text) {
    return text.length;
  }
  return 0;
}
  1. 非空断言不等于类型转换:非空断言只是告诉编译器某个值不为空,不会改变值的实际类型。

  2. 断言的安全性:使用断言时,开发者需要确保断言的正确性,否则可能导致运行时错误。

总结

类型断言和非空断言是TypeScript中强大的工具,它们允许开发者在编译器无法推断出正确类型时提供额外的类型信息。然而,这些特性应该谨慎使用,因为它们会绕过TypeScript的类型安全检查。在大多数情况下,更好的类型设计和类型守卫应该是首选方案。

记住:断言不是类型转换,它不会改变运行时的行为,只是在编译阶段告诉TypeScript如何处理类型。