如何在 TypeScript 中使用类型保护

前言

类型保护是一种 TypeScript 技术,用于获取变量类型的信息,通常用于条件块中。类型保护是返回布尔值的常规函数​​,它接受一个类型并告知 TypeScript 是否可以将其缩小到更具体的值。类型保护具有独特的属性,可以根据返回的布尔值确保被测试的值属于某个集合类型。

类型保护的方式

TypeScript 使用一些内置的 JavaScript 运算符,例如typeofinstanceofin运算符,用于判断对象是否包含某个属性。类型保护使你能够指示 TypeScript 编译器推断特定上下文中变量的特定类型,从而确保参数的类型与你指定的一致。

类型保护通常用于缩小类型范围,与特性检测非常相似,它允许你检测值的正确方法、原型和属性。因此,你可以轻松地弄清楚如何处理该值。

使用类型保护的主要方式有五种:

  • 关键字instanceof
  • 关键字typeof
  • in操作符类型保护
  • 缩小类型保护
  • 自定义类型保护函数

instanceof类型保护

instanceof是一个内置的类型保护,可用于检查某个值是否是给定构造函数或类的实例。使用此类型保护,我们可以测试某个对象或值是否派生自某个类,这对于确定实例类型的类型非常有用。

typescript 复制代码
interface Accessory {
    brand: string;
  }
  class Necklace implements Accessory{
    kind: string;
    brand: string;
    constructor(brand: string, kind: string) {    
      this.brand = brand;
      this.kind = kind;
    }
  }
  class bracelet implements Accessory{
    brand: string;
    year: number;
    constructor(brand: string, year: number) {    
      this.brand = brand;
      this.year = year;
    }
  }
  const getRandomAccessory = () =>{
    return Math.random() < 0.5 ?
      new bracelet('cartier', 2021) :
      new Necklace('choker', 'TASAKI');
  }
  let Accessory = getRandomAccessory();
  if (Accessory instanceof bracelet) {
    console.log(Accessory.year);
  }
  if (Accessory instanceof Necklace) {
    console.log(Accessory.brand);    
  }

上面的函数getRandomAccessory返回一个Necklacebracelet对象,因为它们都实现了该Accessory接口。 和 的构造函数签名Necklace不同braceletinstanceof类型保护会比较两个构造函数签名来有效地确定类型。

typeof类型保护

typeof类型保护用于确定变量的类型。typeof类型保护被认为非常有限且浅显。它只能确定 JavaScript 识别的以下类型:

  • Boolean
  • String
  • Bigint
  • Symbol
  • Undefined
  • Function
  • Number

其他的typeof 类型保护只会返回 object

typeof 类型保护有以下两种写法:

javascript 复制代码
typeof v !== "typename"

typeof v === "typename"
`typename` 可以是 `string` 、 `number` 、 `symbol` 或 `boolean` 。

在下面的示例中, StudentId 具有一个 string | number 类型的联合参数条目。我们可以看到,如果变量是 string ,则打印 Student ;如果变量是 number ,则打印 Idtypeof 类型保护帮助我们从 x 中提取类型:

typescript 复制代码
function StudentId(x: string | number) {
    if (typeof x == 'string') {
        console.log('Student');
    }
    if (typeof x === 'number') {
        console.log('Id');
    }
}
StudentId(`446`); //prints Student
StudentId(446); //prints Id

in​操作符类型保护

in 类型保护检查对象是否具有特定属性,并以此区分不同类型。它通常返回一个布尔值,指示该属性是否存在于该对象中。它用于缩小范围,以及检查浏览器是否支持。

基本语法:

复制代码
propertyName in objectName

在下面的例子中, in 类型保护检查属性 house 是否存在。如果存在,则返回布尔值 true ;如果不存在,则返回 false

ruby 复制代码
"house" in { name: "test", house: { parts: "door" } }; // => true
"house" in { name: "test", house: { parts: "windows" } }; // => true
"house" in { name: "test", house: { parts: "roof" } }; // => true
"house" in { name: "test" }; // => false
"house" in { name: "test", house: undefined }; // => true

另一个 in 类型保护如何工作的类似示例如下所示:

kotlin 复制代码
interface Pupil {
    ID: string;
  }
  interface Adult {
    SSN: number;
  }
  interface Person {
    name: string;
    age: number;
  }
  let person: Pupil | Adult | Person = {
    name: 'Britney',
    age: 6
  };
  const getIdentifier = (person: Pupil | Adult | Person) => {
    if ('name' in person) {
      return person.name;
    }
    else if ('ID' in person) {
      return person.ID
    }
    return person.SSN;
  }

缩小类型保护

通过缩小检查表达式的值,两个变量相等,意味着两个变量的类型必须相同。如果一个变量的类型未知,但它等于另一个具有精确类型的变量,则 TypeScript 会根据已知变量提供的信息缩小第一个变量的类型:

typescript 复制代码
function getValues(a: number | string, b: string) {
    if(a === b) {
        // this is where the narrowing takes place. narrowed to string
        console.log(typeof a) // string
    } else {
        // if there is no narrowing, type remains unknown
        console.log(typeof a) // number or string
    }
}

上面如果变量 a 等于变量 b ,则两者必须具有相同的类型。在这种情况下,TypeScript 会将其范围缩小为字符串。如果不进行范围缩小, a 的类型仍然不明确,因为它可能是数字,也可能是字符串。

自定义类型保护函数

创建自定义类型保护通常是使用类型保护的强大选项。当你自己编写自定义类型保护时,虽然可以检查的内容没有任何限制。但是如果自定义类型保护编写不正确,则可能导致很多的错误。

示例:

typescript 复制代码
interface Necklace{
    kind: string;
    brand: string;
}
interface bracelet{
    brand: string;
    year: number;
}
type Accessory = Necklace | bracelet;

const isNecklace = (b: Accessory): b is Necklace => {
    return (b as Necklace).kind !== undefined
}
const Necklace: Accessory = {kind: "Choker", brand: "TASAKI"};
const bracelet: Accessory = {brand: "Cartier", year: 2021};
console.log(isNecklace(bracelet)) //Logs false
console.log(isNecklace(Necklace)) //Logs true

结论

TypeScript 类型保护有助于确保类型的值,从而改善整体代码流程。大多数情况下,建议使用 instanceof 类型保护、 typeof 类型保护或 in 类型保护来解决,但是,在绝对必要时你可以使用自定义类型保护。

相关推荐
流影ng1 天前
【HarmonyOS】并发线程间的通信
typescript·harmonyos
duansamve1 天前
TS在Vue3中的使用实例集合
typescript·vue3
FanetheDivine2 天前
ts中如何描述一个复杂函数的类型
前端·typescript
struggle20253 天前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell
执剑、天涯3 天前
通过一个typescript的小游戏,使用单元测试实战(二)
javascript·typescript·单元测试
chéng ௹3 天前
Vue3+Ts+Element Plus 权限菜单控制节点
前端·javascript·vue.js·typescript
武清伯MVP4 天前
阮一峰《TypeScript 教程》学习笔记——基本用法
笔记·学习·typescript
ttod_qzstudio5 天前
解决 Vue 3 + TypeScript 中 v-for 循环类型推断问题
前端·vue.js·typescript
今天头发还在吗6 天前
【React】动态SVG连接线实现:图片与按钮的可视化映射
前端·javascript·react.js·typescript·前端框架
冷冷的菜哥6 天前
react多文件分片上传——支持拖拽与进度展示
前端·react.js·typescript·多文件上传·分片上传