文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

五种在 TypeScript 中使用类型保护的方法

2024-11-30 11:35

关注

在这篇文章中,我将介绍 5 种实现类型保护的方法。

01、typeof 类型保护

首先我们来介绍一下比较常见的typeof类型防护。typeof 运算符可以在运行时获取对象的类型,该运算符返回以下可能的值:

因此使用 typeof 运算符,我们可以在运行时获取变量的实际类型。举个例子:

function printId(id: string | number) {
  if (typeof id === "string") {
    console.log(`ID: ${id.toUpperCase()}`);
  } else if (typeof id === "number") {
    console.log(`ID: ${id}`);
  }
}

在上面的代码中,我们定义了一个 printId 函数,它包含一个 id 参数,其类型为字符串 | 数字联合类型。

在函数体中,我们使用 typeof 运算符来确定参数的实际类型。如果id参数是字符串类型,我们会将其值转换为大写后再输出。

那么为什么要使用 typeof 运算符来缩小 id 参数的类型呢?主要原因是为了保证运行时的类型安全。例如,当id参数的类型是数字类型时,但是我们调用id.toUpperCase()方法,就会抛出运行时异常。

在支持 TypeScript IntelliSense 的编辑器中,当您访问 id 参数的某些属性时,只能访问字符串和数字类型的公共属性。具体如下图所示:

02、instanceof 类型守卫

虽然typeof运算符可以区分不同的类型,但如果我们想判断一个对象是否是某个类的实例,从而安全地访问该实例上特有的属性或方法,那么typeof运算符就无能为力了。

对于这个需求,我们可以使用instanceof运算符。再次,我们举一个具体的例子:

class Shape {
  constructor(public id: string) {}
}


class Circle extends Shape {
  constructor(
    public id: string, 
    public radius: number) {
   super(id);
  }
}


class Square extends Shape {
  constructor(
    public id: string, 
    public sideLength: number) {
      super(id);
  }
}

在上面的代码中,我们定义了一个Shape类,并基于它创建了两个子类。接下来,我们定义一个 printShapeInfo 函数来打印有关不同形状的信息:

function printShapeInfo(shape: Shape) {
  if (shape instanceof Circle) {
    console.log(`Circle's radius is: ${shape.radius}`);
  } else if (shape instanceof Square) {
    console.log(`Square's sideLength is: ${shape.sideLength}`);
  }
}

在printShapeInfo函数体中,我们使用instanceof运算符来缩小形状参数的类型,从而输出不同形状的信息。在 if...else if 分支之外,我们只能访问 Circle 对象和 Square 对象共有的 id 属性。

03、in type guards

对于前面使用instanceof运算符实现类型保护的示例,我们还可以使用接口的形式来描述Shape、Circle和Square类型。

interface Shape {
  id: string;
}


interface Circle extends Shape {
  radius: number;
}


interface Square extends Shape {
  sideLength: number;
}

由于TypeScript接口定义的类型在编译后并不会生成对应的类型,因此我们无法在运行时使用instanceof运算符进行类型检测。要实现printShapeInfo函数的功能,我们可以使用in运算符,具体实现如下:

function printShapeInfo(shape: Shape) {
  if ("radius" in shape) {
    console.log(`Circle's radius is: ${shape.radius}`);
  } else if ("sideLength" in shape) {
    console.log(`Square's sideLength is: ${shape.sideLength}`);
  }
}

除了上述方法之外,我们还可以使用可判别联合类型来表示Shape类型:

type Circle = {
  id: string;
  type: "circle";
  radius: number;
};


type Square = {
  id: string;
  type: "square";
  sideLength: number;
};


type Shape = Circle | Square;

在Circle和Square类型中,type属性的类型是字符串文字类型,用于区分不同的形状,称为可区分属性。对于判别联合类型,结合switch…case语句,我们还可以实现printShapeInfo函数对应的功能。

function printShapeInfo(shape: Shape) {
  switch (shape.type) {
    case "circle":
      console.log(`Circle's radius is: ${shape.radius}`);
      break;
    case "square":
      console.log(`Square's sideLength is: ${shape.sideLength}`);
      break;
    default:
      console.log("Unknown shape");
  }
}

介绍完如何使用常见的 typeof、instanceof 和 in 运算符实现类型保护之后,我们来介绍一下如何定义用户自定义的类型保护。

04、用户定义的类型保护

为了演示用户定义的类型保护,让我们重新定义 3 种类型:

interface Shape {
  id: string;
}


interface Circle extends Shape {
  radius: number;
}


interface Square extends Shape {
  sideLength: number;
}

定义完Shape相关的类型后,我们来定义用户自定义的类型保护函数:

function isCircle(shape: Shape): shape is Circle {
  return "radius" in shape;
}


function isSquare(shape: Shape): shape is Square {
  return "sideLength" in shape;
}

与普通函数相比,自定义类型保护函数返回类型谓词。上面代码中的 shape is Circle 就是所谓的类型谓词。谓词采用parameterName is Type 的形式,其中parameterName 必须是当前函数签名中的参数名称。

这样就可以理解isCircle用户自定义类型保护函数的作用了。如果函数返回值为true,则shape参数的类型为Circle类型。

现在我们有了 isCircle 和 isSquare 函数,我们可以在 printShapeInfo 函数中使用它们,如下所示:

function printShapeInfo(shape: Shape) {
  if (isCircle(shape)) {
    console.log(`Circle's radius is: ${shape.radius}`);
  } else if (isSquare(shape)) {
    console.log(`Square's sideLength is: ${shape.sideLength}`);
  }
}

05、相等缩小类型防护

除了前面描述的 4 种类型保护方法之外,TypeScript 还支持使用 if/switch 语句和相等检查,例如 ===、!===、== 和 != 运算符来缩小变量的类型。

function printValues(a: string | number, b: string | string[]) {
  if (a === b) {
    console.log(a.toUpperCase()); // (parameter) a: string
    console.log(b.toUpperCase()); // (parameter) b: string
  } else {
    console.log(a); // (parameter) a: string | number
    console.log(b); // (parameter) b: string | string[]
  }
}

上面的代码中,printValues函数支持a和b 2个参数,并且它们的类型都是联合类型。当a===b表达式的计算结果为true时,参数a和b的类型将缩小为字符串类型。当然,使用!==运算符也可以用来实现类型缩小。

function printValues2(a: string | number, b: string | string[]) {
  if (a !== b) {
    console.log(a); // (parameter) a: string | number
    console.log(b); // (parameter) b: string | string[]
  } else {
    console.log(a.toLowerCase()); // (parameter) a: string
    console.log(b.toLowerCase()); // (parameter) b: string
  }
}

这就是关于 TypeScript 类型防护的全部内容。

总结

以上就是我今天想与你分享的5个TS的知识技能,希望对你有所帮助。

来源:web前端开发内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯