TypeScript(五)类型别名及类型符号

2023-11-17

目录

引言

类型别名

基本用法 

字面量类型

数字字面量

字符串字面量

布尔字面量

空字面量

枚举字面量

类型符号

联合类型

交叉类型

类型断言

尖括号

as关键字

非空断言

类型保护

typeof

instanceof

类型谓词

索引类型

映射类型

type or interface?

二者的区别:

应用场景

总结

参考文章


引言

本文收录于TypeScript知识总结系列文章,欢迎指正! 

在编写JS代码时,我们通常使用const、var、let来定义一个变量,进行变量的运算或者逻辑编写等。在TS中也有一种类似变量的写法那就是类型别名,与运算逻辑相对应的便是类型符号

类型别名

在前面的文章中,我们介绍了TypeScript中常用的类型,然而在实际项目开发中,不可避免的会遇到各种复杂类型,有些可以使用接口或对象类型来描述,但是有些数据类型更灵活、复杂,那么此时,类型别名是一种非常有用的工具,它可以帮助我们简化代码,提高代码的可读性和可维护性;

基本用法 

类型别名使用 type 类型名 = 类型值 的方式来定义,如

interface IFn {
    (): void
}
interface IDog {
    name: string
    age?: number
    [key: string]: unknown
}
type myStr = string// 字符串
type myNum = number// 数字
type myArr = string[]// 数组
type myFn = IFn// 函数
type myDog = IDog// 接口
type myObj = {
    str: string
    num: number
    arr: myArr
}// 对象
const str: myStr = "string"
const num: myNum = 10
const arr: myArr = ['a', 'b']
const fn: myFn = () => null
const dog: myDog = {
    name: "阿黄"
}
const obj: myObj = {
    str: "string",
    num: 11,
    arr: arr
}

字面量类型

字面量类型(Literal Types)用来表示具体的字面量值,包括字符串、数字、布尔值等。它们可以作为类型注解的一部分,用来限制变量、函数参数、函数返回值等的取值范围

数字字面量

数字字面量类型(Numeric Literal Types)是一种用来表示具体数字值的类型,它使用一个具体的数字来定义一个类型

type Num = 10
const num: Num = 10
const num2: Num = 20 // 抛错,不能将20赋值给类型10

字符串字面量

字符串字面量类型(String Literal Types):用来表示一个具体的字符串值的类型。

type Str = "a"
const num: Str = "a"

布尔字面量

布尔字面量类型(Boolean Literal Types):用来表示一个具体的布尔值的类型。

type Bool = false
const bool: Bool = false

空字面量

空字面量类型(Empty Literal Types):用来表示一个空值的类型,被定义的类型只能被赋值为undefinednull

type Void = void;
const isNull: Void = null
const isUndefined: Void = undefined
const isVoid: Void = void 0

枚举字面量

枚举字面量类型(Enum Literal Types):用来表示一个具体的枚举值的类型

enum Color {
    Red = 1,
    Green,
    Blue
}
type colorBlue = Color.Blue
const blue: colorBlue = 3

类型符号

如果说类型别名是一个人,那么类型符号就是它的灵魂。在TypeScript中,类型符号是构建类型系统的基础,是实现类型别名的核心。

联合类型

联合类型(Union Types)用来表示一个变量可以包含多种类型之一的情况。联合类型使用或符号 |  来连接两个或多个类型,例如:

let strOrNum: string | number = 10
strOrNum = "a"

我们使用上面讲到的类型别名试试

type strOrNum = string | number
const str: strOrNum = "a"
const num: strOrNum = 10

交叉类型

交叉类型(Intersection Types)可以用来将多个类型合并为一个类型。交叉类型使用且符号&进行连接两个或多个类型;值得注意的是交叉类型一般使用于对象定义这种复杂的数据类型,如果使用交叉类型定义基础类型,则会转换为never类型,因为一个类型不可能同时兼备两种基础类型,如

type str = string
type num = number
type StrAndNum = str & num // never类型

上面代码中number和string是互斥的类型,不存在既是number又是string的值,然而程序不会逻辑报错,因为number和string会包装成对象类型

下面是一个交叉类型的案例

type Animal = {
    name: string
    age?: number
}
type Dog = {
    readonly color: string
    getColor(): string
}

type WhiteDog = Animal & Dog

const whiteDog: WhiteDog = {
    name: "阿黄",
    color: "white",
    getColor() {
        return this.color
    },
}

tips:交叉类型和接口继承有点类似,如果对象同时存在同名不同类型的属性时会抛错 

类型断言

类型断言(Type Assertion)是一种显式地告诉编译器变量的类型的方式,它允许我们手动指定一个变量的类型,从而绕过TypeScript编译器对该变量类型的检查。

断言的使用方式有两种,分别是尖括号和as关键字

尖括号

let str: unknown
const len: number = (<string>str).length

在上面的代码中,我们使用断言的方式将str转换为字符串类型,并获取字符串的长度

as关键字

let str: unknown
const len: number = (str as string).length

与尖括号一样,在变量的后面增加 as 类型 使用类型断言

非空断言

在JS中,我们通常使用可选链操作符( .? )来判断一个对象是否为空,来增加代码健壮性

在TS中,我们可以使用非空断言(Non-null Assertion)来告诉编译器变量或表达式一定不为空

在下面代码中,str可能是null或者字符串类型,若直接使用str.length会提示:对象可能为"null"

const str: string | null = null
const len: number = str.length

tips:上述代码没抛错可能因为在tsconfig中未开启strictNullChecks

此时我们可以通过 ! 非空断言或 ? 可选链操作符以及 ?? 空值合并操作符告诉编译器str不为null或处理变量为空的异常

let str: string | null = null
if (window) {
    str = "abc"
}
const len: number = str!.length
const len2: number = str?.length ?? 10

类型保护

typeof

TypeScript的typeof和JavaScript的typeof在语法上是相同的,但是在行为上有区别。在TS中typeof可以获取变量的类型,如

let num = 10
let str = 'abc'
type myStr = typeof str
type myNum = typeof num
const str1: myStr = "bcd"
const num1: myNum = 20

instanceof

instanceof与JS中的使用方式相同,animal instanceof Animal 表示animal是不是Animal的实例化对象,这里就不多赘述

class Animal { }
const animal = new Animal()
console.log(animal instanceof Animal);

类型谓词

类型谓语在函数运行时检查返回值的类型,并且进行类型保护,它的作用是缩小类型范围。类型谓语使用is表示,下面是一个简单的例子

interface IAnimal {
    name: string
    age: number
}
function isAnimal(animal): animal is IAnimal {
    return "name" in animal
}
const animal: any = {
    name: '阿黄',
    age: 10
};

if (isAnimal(animal)) {
    console.log(animal.name)
}

可以看到,我们定义了一个IAnimal接口,其中有两个属性,在isAnimal函数中我们把函数返回值写成类型谓语的形式,表示返回值的animal就是接口IAnimal的实现,此时在下方取animal.name时是正常的。

此时我们重新定义一个接口IDog

interface IDog {
    color: string
    hobby: string
}

将上面的isAnimal函数改成这样,此时再执行isAnimal函数后,再去访问name属性就会抛错

function isAnimal(animal): animal is IDog {
    return "name" in animal
}
if (isAnimal(animal)) {
    console.log(animal.name) //报错,类型“IDog”上不存在属性“name”
}

除此之外我们同样可以结合交叉类型,联合类型等灵活的使用is

索引类型

在TS中我们可以使用keyof关键字来获取一个对象类型或接口的类型的所有键的联合类型。

interface IDog {
    name: string
    color: string
    age: number
}
type IDogKeys = keyof IDog // 相当于 'name' | 'color' | 'age'
const dogAge: IDogKeys = "age"
const dogColor: IDogKeys = "color"
const dogName: IDogKeys = "name"

上述代码的IDogKeys相当于获取了IDog的所有键的联合类型,使用类型别名描述对象的方式同样可以达到效果

type IDog = {
    name: string
    color: string
    age: number
}

type IDogKeys = keyof IDog // 相当于 'name' | 'color' | 'age'
const dogAge: IDogKeys = "age"
const dogColor: IDogKeys = "color"
const dogName: IDogKeys = "name"

映射类型

in运算符在TypeScript和JavaScript中都存在,并且用法基本相同,用来检查某个属性是否存在于某个对象或其原型链中

interface IDog {
    name: string
    color?: string
}
const dog: IDog = {
    name: "阿黄"
}
console.log('name' in dog);// true
console.log('color' in dog);// false

使用索引类型加映射类型限制索引区间

interface IDog {
    name: string
    color?: string
}
type ISmallDog = {
    [key in keyof IDog]: string// 这行表示只能取IDog的key
}
const dog: ISmallDog = {
    name: "阿黄",//此时的type需要与ISmallDog的相同
    hobby: 'ball'// 报错,IDog找不到hobby
}

type or interface?

Type和Interface都是用于定义类型的关键字,那么其二者分别适用什么场景?

二者的区别:

  • Type可以声明基本类型、联合类型、元组、枚举、函数等,而Interface主要用于定义对象、类、函数等复杂类型
  • Type是类型别名的作用,不能被扩展,而Interface可以被继承
  • Type可以使用联合类型,交叉类型等高级类型进行操作,而Interface不支持

应用场景

Type:定义一个基本类型、联合类型、元组、枚举等类型,或需要使用高级类型操作的类型

Interface:定义对象、类等复杂类型,或使用对类型扩展,继承等操作时接口更适用

tips:使用type定义的对象类型同样可以被类实现

type IAnimel = {
    name: string
    getName(): string
}
class Animal implements IAnimel {
    name = 'dog'
    getName() {
        return this.name
    }
}

总结

本文从类型别名和类型符号两个模块;介绍了类型别名的使用及字面量类型,并且从联合类型,交叉类型等高级类型操作的方面将类型别名的应用场景连接起来,最后将类型别名对比接口介绍了二者的使用场景

感谢你看到了最后,有任何问题可以在评论区讨论,如果文章对你有帮助,还望多多支持一下!

参考文章

高级类型 - TypeScript 中文手册

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript(五)类型别名及类型符号 的相关文章

  • 使用 Gmail 上下文小工具访问附件

    我想将电子邮件及其附件从 Gmail Google Apps 保存到另一个数据库以实现类似 CRM 的功能 然而 根据docs http code google com apis gmail gadgets contextual 提取器无法
  • 检测对给定 JavaScript 事件的支持?

    我有兴趣使用 JavaScript hashchange 事件来监视 URL 片段标识符的更改 我知道非常简单的历史 http code google com p reallysimplehistory 以及用于此目的的 jQuery 插件
  • 将 Json 数据返回给 Ajax 调用

    我在 MVC 中有一个方法 我将其发布到它 并且我需要返回一些数据以进行处理 这是我发布到的 MVC 方法 返回值是 json 数据 HttpPost public JsonResult GetCalculateAmortizationSc
  • 如何在单页应用程序中使用 #-URL?

    本文 http danwebb net 2011 5 28 it is about the hashbangs提出了一个非常令人信服的论点 因为 URL 是长期存在的 它们被添加书签并传递 所以它们应该是有意义的 并且使用哈希进行真正的路由
  • mocha.opts 已弃用,如何迁移到 package.json?

    我正在开发一个大型项目 自从上周我更新了摩卡以来 现在我们收到警告 DeprecationWarning 通过 mocha opts 进行的配置已被弃用并且 将从 Mocha 的未来版本中删除 使用 RC 文件或 改为 package js
  • 错误 TS2314:通用类型“Component”需要 2 个类型参数

    在将 ReactJS 与 TypeScript 一起使用时 会出现以下错误 error TS2314 Generic type Component
  • 通过 Javascript 更改 Webkit 属性?

    请帮助我 可能是因为我对 CSS 动画和 Javascript 相当陌生 但我使用的代码应该更改它的属性 当我运行代码时 它会执行代码中的所有其他操作 除了更改所需 div 的 CSS 属性 我已经尝试了所有这四种方法 但似乎都不起作用 它
  • 找不到本地“typescript”包。“@ngtools/webpack”包 Angular 2

    我在这里搜了一下 Angular 2 ngtools webpack AOT https stackoverflow com questions 42651383 angular 2 ngtools webpack aot 但对我不起作用
  • Javascript 制作音频 blob

    我正在测试 html 音频标签 我想制作音频 blob url 就像 youtube 或 vimeo 那样 并将其添加到 src 开始播放音频 我一直在测试new Blob and URL createObjectURL 但我不知道如何使用
  • Chrome 跨域 PATCH 请求不起作用

    我有一个带有 REST Api 的网站 现在我正在创建一个浏览器扩展 它将从某些页面收集数据并将它们发送回 REST Api 因为我希望我的扩展能够与 Firefox 和 Chrome 兼容 并且易于维护 所以我将实际代码作为脚本标记注入到
  • 处理时区转换的 JavaScript 库

    是否有一个 JavaScript 库可以处理时区转换 并考虑 DST 规则和此类内容 我知道有类似的问题 但我见过的问题似乎都没有真正适合我的问题的答案 我想在时区 A 创建一个日期并能够对其进行操作 添加天数 小时等 然后将其转换为另一个
  • dc lineChart 单击时弹出数据点信息

    我正在尝试检测折线图数据点上的点击 Per this answer dc scatter plot binding onClick event https stackoverflow com a 22772340 1873386 I am
  • 如何获取 Spotify API 的访问令牌?

    我已经研究 Spotify api 和示例源代码几天了 但我仍然不知道如何获取访问令牌来访问用户的播放列表数据 我已经到达了拉起登录窗口 用户登录 然后收到授权码的地步 此时 我尝试做这样的事情 window open https acco
  • Flask 和 Reactjs 抛出 JSX 转换错误

    我已经开始将 ReactJS 与 Python Flask 后端结合使用 通过 Flask 渲染模板时 我在 Chrome 控制台中收到以下客户端错误 错误 找不到模块 jstransform visitors es6 templates
  • 在 Windows 上静默安装 Qt55 Enterprise

    编辑 在 Qt 支持的帮助下 我已经解决了如何自动化 Qt 企业安装程序的这两个部分 下面是脚本调用 我正在尝试在 Windows 8 1 和 Windows 10 上静默安装 Qt 5 5 1 Enterprise 使用 script 开
  • 带有桌子的嵌套表

    我在应用了表排序器的表中嵌套了表 它在嵌套表中添加了排序标题 但是它们没有对行进行排序 并且抛出了JavaScript错误 我想拥有 嵌套表不可排序 巢表上的排序实际上可以工作 但不是现状 您的第一个选择要容易得多 使嵌套表不可排序 像这样
  • jQuery 模板插件:如何创建双向绑定?

    我开始使用 jQuery 模板插件 微软创建的 但现在我面临这个问题 模板用于绑定到对象数组的一堆表单 当我更改其中一个表单上的某些内容时 我希望更新绑定的对象 但我不知道如何自动执行该操作 这是一个简单的例子 现实生活中的模板和对象要复杂
  • Jquery Ajax 调用返回 403 状态

    我有一个 jquery Ajax 调用来实现会话的 keepalive 这个 keepAlive 方法将每 20 分钟调用一次 function keepAlive ajax type POST url KeepAliveDummy asp
  • Dojo“正在加载”消息

    我是 Dojo 新手 所以我需要一些帮助 我的一些链接需要一段时间 当用户单击时 页面开始加载需要几秒钟 我想添加一条 正在加载 消息 我可以用 旧时尚方式 来做 但我想学习新的 更简单 更智能的 Dojo 方式 具体如何工作现在并不重要
  • 如何更改数据表中标题单元格的内容?

    我正在使用数据表 http datatables net plugin 在我的可排序列上 我想用按钮替换列文本 但是这样做 oSettings aoColumns i nTh text 我可以检索相应列的文本 但是 oSettings ao

随机推荐

  • 03-----C/C++ 实现可变参数的函数

    头文件 C include
  • 有关HDX-介绍而已

    what is HDX First and foremost HDX is not a feature or a technology it is a brand Short for High Definition Experience H
  • HTTPweb服务器——HTTP整体设计框架

    我们整个的项目采用B S模式 通过浏览器发送HTTP的get方法和post方法 然后server进行响应 这样最终通过html看到我们所显示的最终的效果 另外 为了支持并发 我们采用了多线程的结构 1 进行创建监听套接字 和其他socket
  • Android button靠右侧显示

    注 要在包含button的父布局中设置
  • SpringCache 使用Redis作为缓存技术的使用

    介绍 Spring Cache是一个框架 实现了基于注解的缓存功能 只需要简单地加一个注解 就能实现缓存功能 大大简化我们在业务中操作缓存的代码 Spring Cache只是提供了一层抽象 底层可以切换不同的cache实现 具体就是通过Ca
  • Unity地图设计和关卡顺序解锁以及分支解锁最好理解的实现(PlayerPrefs.GetInt与PlayerPrefs.SetInt应用及内容查询)

    Unity地图设计和关卡解锁最好理解的实现 PlayerPrefs GetInt与PlayerPrefs SetInt应用及内容查询 这里说一种类似于森林冰火人的解锁机制 也就是中心的关卡先解锁 中间的通过了四周解锁一个 然后一个接一个解锁
  • 微信小程序密码显示隐藏(小眼睛)

    一 效果图 微信小程序密码显示隐藏 小眼睛 二 代码 wxml
  • 如何使用vs将现有的项目或者文件夹(尤其是多层目录的)添加到项目中

    困扰我这么久的问题 哎 真心弱爆了 1 将现有项目或文件夹拷贝到指定目录下 2 解决方案右上有个显示所有文件的按钮 然后选中所有要添加的文件 右击 选择包含到项目中即可
  • react 函数组件props的使用

    函数组建的props 1 如何给组件传递数据 给组建的标签添加属性即可 2 函数组件通过props参数就能接受 也可以通过解构props function App props return div h1 我是App组件 props name
  • 层次分析法基本介绍

    层次分析法 1 主要解决哪类问题 评价类 评价类问题要明确 评价的目标是什么 为达到这个目标的可选方案 评价的准则或标准是什么 2 原理 思路是啥 eg 小明高考完如何选择一个学校 如何选择一个旅游目的地 可以思考到 并得到表格 定义指标
  • PDF批量替换文字器免费版

    安装教程 1 下载解压后 得到文件 pdfreplacer exe 双击进入安装向导 2 选择语言 完成后确认进入下一步 3 下一步 4 系统默认安装在C盘 单击浏览可自定义选择安装路径 随后下一步 5 是否创建桌面快捷方式 建议选上 下一
  • PCB板基础知识

    制作机器人的时候不可避免的会用到PCB板 之前对它的认识只停留在会用这个层面 最近学习了PCB板的制作 发现了之前很多不知道的知识 于是整理出来和大家分享 1 过孔 双层板的连接通道 这个是之前最摸不着头脑的环节 拿到一个PCB就会发现上面
  • 拼接滚动地图-Quick-cocos2dx

    lua里面class的使用 一个class的使用 class方法用于创建类 其实就是lua表 传入类名和父类 父类为方法或表 class使用 第一次用A class fun 第二次用a A new 示例 local LevelView cl
  • SpringBoot之@Slf4j的使用详解

    先简单的来说 作用 Slf4j是在SpringBoot基础上Lombok为我们提供的日志输出注解 使用 先引入lombok依赖 将注解添加在类上 然后就可以使用log info 进行日志的输出打印 Slf4j注解填在当前类上相当于Sprin
  • vscode使用ssh远程linux可视化开发环境搭建

    目录 1 搭建 vscode 远程开发流程 2 在线搭建环境 3 离线搭建环境 4 ssh免密登录 设置白名单 5 参考文档 最近一直在做服务引擎开发 编译都是在服务器linux环境中进行 每次调试使用gdb修改使用vim贼麻烦 最后找了下
  • 10种Arduino IDE替代品开始编程

    当我们开始开发Arduino项目时 通常我们倾向于使用Arduino IDE 无论如何 如果我们对标准IDE不满意 我们应该考虑几种Arduino IDE替代方案 众所周知 在开发物联网项目或构建DIY项目时 Arduino是最受欢迎的原型
  • ARM指令集

    ARM指令的基本格式 ARM指令的基本格式为
  • echarts之柱状图(1)

    PS相关学习资料链接 Pink老师的教程分解 O O哈哈 div class bar h2 就业行业 a href 2019 a a href 2020 a h2 div class chart div div css自行设置 类名为cha
  • Failed to execute goal on project rocketmq-console-ng: Could not resolve dependencies for project

    Apache RocketMQ安装部署 Failed to execute goal on project rocketmq console ng Could not resolve dependencies for project org
  • TypeScript(五)类型别名及类型符号

    目录 引言 类型别名 基本用法 字面量类型 数字字面量 字符串字面量 布尔字面量 空字面量 枚举字面量 类型符号 联合类型 交叉类型 类型断言 尖括号 as关键字 非空断言 类型保护 typeof instanceof 类型谓词 索引类型