TypeScript类型断言VS类型守卫示例详解

目录
  • 类型断言
  • 类型守卫
    • 使用 in 关键字
    • 使用 instanceof 关键字
    • 使用 typeof 关键字
    • 自定义类型守卫
  • 总结

类型断言

类型断言有两种写法,分别为value as Type<Type>value,它让 TypeScript 编译器将 value 当作 Type 类型。类型断言是一个编译时特性,不进行类型转换,因此不会影响变量在运行时的数据类型。如果某变量是 any 类型,但现在你知道它确切的数据类型,使用类型断言能让 IDE 有代码提示的能力,也能让 TypeScript 编译器进行类型检查。

类型断言的用法如下:

const age: any = 23.44;
const user: any = {age: 2}
// age 的 原始数据类型是 any ,在这里将它断言为 number 类型
(age as number).toFixed(0);
(<number>age).toFixed(0);
// 将user断言为非null和非undefined
user!.age

除非确切的知道变量的数据类型,否则不要使用类型断言,这是因为类型断言会让 TypeScript 编译器将变量当做指定的类型,而不管它实际的类型,在程序运行时可能有类型错误。

类型守卫

类型守卫的工作是将数据类型收窄,比如,变量 age 的数据类型可能是 string 也可能是 number,现在要将 age 收窄为 string 类型,类型守卫能实现它。总体而言,有4种方式让数据类型收窄。

使用 in 关键字

如果某变量的数据类型是联合类型,并且该变量存在一个属性绝对不会出现在联合类型的其他成员类型上,那么可以使用 in 关键字将类型收窄。用法如下:

function printType(value: User | Student) {
    // grade 只存在 Student 类型上
if ('grade' in value) {
        // 在 if 块中,value 的数据类型被收窄为 Student 类型
        console.log('它是 Student 类型',value.name + ':' + value.grade)
    } else {
	// 在 else 块中,value 的数据类型被收窄为 User 类型
        console.log('它是 User 类型',value.name)
    }
}

使用 instanceof 关键字

用 in 关键字收窄数据类型有局限性,必须有一个独特的属性作为判别符,否则,不能用 in 关键字收窄。如果正在处理的变量是类的实例,那么可以用 instanceof 关键字收窄数据类型。用法如下:

function printInfo(value: Staff | Student) {
    if (value instanceof Staff) {
        // 在 if 块中,value 的数据类型被收窄为 Staff 类型
        console.log('它是 Staff 类型')
    } else {
        // 在 else 块中,value 的数据类型被收窄为 Student 类型
        console.log('它是 Student 类型')
    }
}

使用 typeof 关键字

使用 typeof 能得到值的数据类型,如果变量的类型为基本类型,如:string、number 等,使用 typeof 也能将数据类型收窄。用法如下:

function printType(value: string | number) {
    if (typeof value === 'string') {
        // value 的类型被收窄为 string
        console.log('value 是 string 类型')
    } else {
        // value 的类型被收窄为 number
        console.log('value 是 number 类型')
    }
}
// 用对象上某个字段收窄数据类型
//如果 User 类型的 name 字段为 string 类型,Student 类型的 name 字段为 number 类型
function printObjType(obj: User | Student) {
    if (typeof obj.name === 'string') {
        // value 的类型被收窄为 User
    } else {
        // value 的类型被收窄为 Student
    }
}

自定义类型守卫

用 in、instanceof 和 typeof 关键字收窄数据类型语法很简单,但都有各自的局限性。如果它们不能当作类型守卫,那么能使用 is 关键字自定义类型守卫,写法为:parameter is Type,这种写法被称为类型谓词,要将它放在函数返回值的位置。

类型谓词所在的函数被称为类型谓词函数,它的返回值必须为 boolean 类型。类型谓词中的 Type可以是任意合法的 TypeScript 数据类型,parameter 可以是函数的参数也能是 this 关键字。

当类型谓词中的 parameter 是函数的参数,用法如下:

function predicateStudent(value: Student | User): value is Student {
    return typeof (value as any).garde === 'number'
}
function printObjType(obj: User | Student) {
    if (predicateStudent(obj)) {
        // obj的类型被收窄为 Student
    } else {
        // value 的类型被收窄为 User
    }
}

上述代码中的 predicateStudent 是类型谓词函数,如果它返回 true,那么参数的数据类型被收窄为 Student。

当类型谓词中的 parameter 是 this 关键字,这种用法通常出现在类的方法中,用法如下:

abstract class User {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    isStudent(): this is Student {
        return this instanceof Student;
    }
    isStaff(): this is Staff {
        return this instanceof Staff;
    }
}
class Student extends User{
    grade: number;
    constructor(name: string, grade: number) {
        super(name)
        this.grade = grade
    }
}
class Staff extends User {
    salary: number;
    constructor(name: string, salary: number) {
        super(name)
        this.salary = salary
    }
}
function printObjType(obj: User) {
    if (obj.isStaff()) {
        // obj 的类型被收窄为 Staff
    } else if (obj.isStudent()){
        // obj 的类型被收窄为 Student
    }
}

上述代码中的 User 是抽象类,不能被实例化,Staff 和 Student 都继承自 User。实例方法 isStaff 用于将类型收窄为 Staff,实例方法 isStudent 用于将类型收窄为 Student。

总结

在项目中,如果某变量有多种数据类型,不建议使用类型断言将它断言成特定的类型,而是使用类型守卫根据实际情况将类型收窄,然后按不同的类型分别处理。类型守卫能让应用程序的数据类型更安全,不至于程序在编译阶段不报错,但在运行阶段报错。

以上就是TypeScript类型断言VS类型守卫示例详解的详细内容,更多关于TypeScript类型断言类型守卫的资料请关注我们其它相关文章!

(0)

相关推荐

  • TypeScript 内置高级类型编程示例

    目录 TypeScript 类型编程 TypeScript 内置高级类型 Pick<Type, Keys> Exclude<UnionType, ExcludedMembers> ReturnType<Type> 更多类型体操学习 TypeScript 类型编程 TypeScript 的类型系统,最基本的是简单对应 JavaScript 的 基本类型,比如 string.number.boolean 等,然后是新增的 tuple.enum.复合类型.交叉类型.索引类型等

  • TypeScript的类型指令单行注释详解

    目录 正文 @ts-ignore 和 @ts-expect-error @ts-check 和 @ts-nocheck 正文 单行注释应该在项目里用的很少吧, 我没见过在项目中使用过, 但是了解一下又不吃亏! 那么一起来看看吧!这里开启了TypeScript提示器. 这里谈谈我对它的理解,也可以看看林不渡的TypeScript小册 一般单行注释是以@ts-开头 @ts-ignore 和 @ts-expect-error @ts-ignore 和 @ts-expect-error 仅仅对紧随其后的

  • Zod进行TypeScript类型验证使用详解

    目录 引言 什么是类型验证,为什么需要它? 为什么要使用zod? 使用 Zod 进行类型验证的示例 Primitives 对象 类型推断 组合类型 注意事项 安全解析 无法识别的Key被删除 其他事项 Zod 与其他库的比较 结论 引言 这篇文章将描述如何使用Zod为您的项目设置类型验证.Zod 是一个用于类型声明和验证的开源 TypeScript 库.我们将研究为什么使用 Zod 进行类型验证,提供如何使用它的示例,并将其与其他库进行比较. 什么是类型验证,为什么需要它? 类型验证是验证数据结

  • TypeScript类型系统自定义数据类型教程示例

    目录 TypeScript 类型系统和自定义数据类型 什么是类型系统 函数类型 类型别名 可选参数 默认参数 函数重载 接口类型 可选属性 只读属性 接口扩展 多重接口声明 接口的索引签名 用接口描述函数 类类型 implements关键字 类的静态端类型和实例端类型 将 this 作为类型 将 this 作为参数 枚举 枚举类型 枚举的成员类型 枚举的成员 字面量类型 联合类型 交叉类型 泛型 泛型函数 泛型接口 泛型类 在工厂函数中使用泛型 泛型约束 在泛型约束中使用类型参数 在泛型中使用条

  • TypeScript实用技巧 Nominal Typing名义类型详解

    目录 Nominal Typing(名义类型) 概念解析 拓展应用 在Vue中的应用 Nominal Typing(名义类型) 概念解析 意思是给一个类型附加上一个“名义”,从而防止结构类型在某些情况下由于类型结构相似而被错用.假设有如下代码: interface Vector2D { x: number, y: number }; interface Vector3D { x: number, y: number, z: number }; function calc(vector: Vect

  • TypeScript类型断言VS类型守卫示例详解

    目录 类型断言 类型守卫 使用 in 关键字 使用 instanceof 关键字 使用 typeof 关键字 自定义类型守卫 总结 类型断言 类型断言有两种写法,分别为value as Type和<Type>value,它让 TypeScript 编译器将 value 当作 Type 类型.类型断言是一个编译时特性,不进行类型转换,因此不会影响变量在运行时的数据类型.如果某变量是 any 类型,但现在你知道它确切的数据类型,使用类型断言能让 IDE 有代码提示的能力,也能让 TypeScrip

  • TypeScript新语法之infer extends示例详解

    目录 正文 模式匹配 提取枚举的值的类型 总结 正文 我们知道,TypeScript 支持 infer 来提取类型的一部分,通过模式匹配的方式. 模式匹配 比如元组类型提取最后一个元素的类型: type Last<Arr extends unknown[]> = Arr extends [...infer rest,infer Ele] ? Ele : never; 比如函数提取返回值类型: type GetReturnType<Func extends Function> = F

  • 使用TypeScript实现一个类型安全的EventBus示例详解

    目录 前言 准备工作 目标 思路 具体实现 全部代码 后记 前言 随着vue3的发布,TypeScript在国内越来越流行,学习TypeScript也随即变成了大势所趋.本文就通过实现一个类型安全的EventBus来练习TypeScript,希望对小伙伴们有所帮助. 准备工作 生成一个TypeScript的基础架子: // 创建目录 mkdir ts-event-bus && cd ts-event-bus // 初始化工程 yarn init -y // 安装typescript yar

  • ts 类型体操 Chainable Options 可链式选项示例详解

    目录 问题 答案 传参 option部分 get 问题 在JavaScript我们通常会使用到可串联(Chainable/Pipline)的函数构造一个对象,但是在Typescript中,你能合理地给它赋上类型吗? 题目是: 可以使用任何你喜欢的方式实现这个类型 - interface, type, 或者 class 都行.你需要提供两个函数option(key, value) 和 get() 在 option 中你需要使用提供的key和value来扩展当前的对象类型,通过 get()获取最终结

  • mybatis写xml时数字类型千万别用 !=‘‘(不为空串)进行判断的示例详解

    前言 最近项目内更新数据时,发现数字类型字段设置为0时不能正常的更新进数据库,我们打印了下mybatis的sql日志发现字段为0的sql没有被拼接. 样例 下面的是错误示例 ❌ <update id="update" parameterType="com.chengfengfeng.test.domain.People"> update people set <if test="age!=null and age !=''"&g

  • Go语言基础类型及常量用法示例详解

    目录 基础类型 概述 按类别有以下几种数据类型 数值类型 派生类型 变量 概述 单个变量声明 多个变量声明 基础类型 概述 在 Go 编程语言中,数据类型用于声明函数和变量.数据类型的出现时为了把数据分成所需要用大数据的时候才需要申请大内存,这样可以充分的列用内存. 按类别有以下几种数据类型 数值类型 布尔型 bool:布尔型的值只可以是常量 true 或者 false,默认值为 false. 字符串类型 string:编码统一为 UTF-8 编码标识 Unicode 文本,默认值为空字符串.

  • java开发ShardingSphere的路由引擎类型示例详解

    目录 ShardingSphere的路由引擎类型 路由引擎类型 标准路由 路由逻辑 总结 ShardingSphere的路由引擎类型 本篇文章源码基于4.0.1版本 上篇文章我们了解到了ShardingSphere在路由流程过程中,根据不同类型的SQL会现在不同的路由引擎,而ShardingSphere支持的路由规则也很多了,包括广播(broadcast)路由.混合(complex)路由.默认数据库(defaultdb)路由.无效(ignore)路由.标准(standard)路由以及单播(uni

  • TS 类型兼容教程示例详解

    目录 类型兼容 简单类型兼容 普通对象兼容 函数兼容 参数数量不一致 参数类型不一致 返回不同 类型兼容 因为JS语言不慎过于领过, 真实开发场景中往往无法做到严格一致的类型约束,此时TS就不得不做类型兼容 顶类型:unknown -- 任何类型都可以赋值给unknown 底类型:never -- never兼容任何类型(可以赋值给任何类型) any: 其实不是一个类型,它是一个错误关闭器,用了any就等同于放弃了类型约束 简单类型兼容 子集可以赋值给父级 type name = string

  • TypeScript 泛型推断实现示例详解

    目录 前言 基础类型准备 最终使用的方式 基于Interface的实现 (失败了) 所有内容都基于type 实现 完整Demo 结束语 前言 最近做东西都在用ts,有时候写比较复杂的功能,如果不熟悉,类型写起来还是挺麻烦的.有这样一个功能,在这里,我们就不以我们现有的业务来举例了,我们还是已Animal举例,来说明场景.通过一个工厂来创建不同的动物实例.在这里我们借助泛型来实现类型的约束和动态推到指定类型. 基础类型准备 用一个枚举来定义Animal的类型 enum EAnimalType {

  • Go 类型转化工具库cast函数详解

    目录 1. cast是啥 2. 两种API 3. 源码分析 1. cast是啥 cast 是在Github上开源的工具库,就像他的名字一样,他为我们提供了非常便捷的类型转化的方法. 我们可以通过下面的地址拉取cast库: go get github.com/spf13/cast 2. 两种API cast库中为我们提供了两类常用的API:cast.Toxxx以及cast.ToxxxE(xxx是要转化成的数据类型). cast.ToxxxE在返回转化后数值的同时,也会返回一个error,cast.

随机推荐

其他