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

简介: TypeScript(五)类型别名及类型符号

引言

本文收录于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
    }
}

总结

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


相关文章
|
2月前
|
JavaScript
typeScript进阶(9)_type类型别名
本文介绍了TypeScript中类型别名的概念和用法。类型别名使用`type`关键字定义,可以为现有类型起一个新的名字,使代码更加清晰易懂。文章通过具体示例展示了如何定义类型别名以及如何在函数中使用类型别名。
39 1
typeScript进阶(9)_type类型别名
|
2月前
|
JavaScript
typeScript基础(2)_any任意值类型和类型推论
本文介绍了TypeScript中的`any`任意值类型,它可以赋值为其他任何类型。同时,文章还解释了TypeScript中的类型推论机制,即在没有明确指定类型时,TypeScript如何根据变量的初始赋值来推断其类型。如果变量初始化时未指定类型,将被推断为`any`类型,从而允许赋予任何类型的值。
56 4
|
1月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
45 0
|
1月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
2月前
|
JavaScript
typeScript基础(5)_对象的类型-interfaces接口
本文介绍了TypeScript中接口(interfaces)的基本概念和用法,包括如何定义接口、接口的简单使用、自定义属性、以及如何使用`readonly`关键字定义只读属性。接口在TypeScript中是定义对象形状的重要方式,可以规定对象的必有属性、可选属性、自定义属性和只读属性。
40 1
|
2月前
|
存储 JavaScript
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
44 0
|
2月前
|
JavaScript
typeScript进阶(10)_字符串字面量类型
本文介绍了TypeScript中的字符串字面量类型,这种类型用来限制变量只能是某些特定的字符串字面量。通过使用`type`关键字声明,可以确保变量的值限定在预定义的字符串字面量集合中。文章通过示例代码展示了如何声明和使用字符串字面量类型,并说明了它在函数默认参数中的应用。
36 0
|
2天前
|
JavaScript 安全 前端开发
TypeScript类型声明:基础与进阶
通过本文的介绍,我们详细探讨了TypeScript的基础与进阶类型声明。从基本数据类型到复杂的泛型和高级类型,TypeScript提供了丰富的工具来确保代码的类型安全和可维护性。掌握这些类型声明能够帮助开发者编写更加健壮和高效的代码,提高开发效率和代码质量。希望本文能为您在使用TypeScript时提供实用的参考和指导。
10 2
|
16天前
|
JavaScript 开发者
在 Babel 插件中使用 TypeScript 类型
【10月更文挑战第23天】可以在 Babel 插件中更有效地使用 TypeScript 类型,提高插件的开发效率和质量,减少潜在的类型错误。同时,也有助于提升代码的可理解性和可维护性,使插件的功能更易于扩展和升级。
|
27天前
|
JavaScript 前端开发
TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第11天】TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!