TS进阶篇 | TS高级类型之字面量类型、联合类型、交叉类型(上)

简介: TypeScript中除了基本类型之外,还定义了很多高级类型,高级类型包括字面量类型、联合类型、交叉类型、索引类型、映射类型、条件类型、this类型等。因为内容太多,所以这篇文章先来介绍前三个类型,其余类型会在高级类型的下篇介绍。

TypeScript中除了基本类型之外,还定义了很多高级类型,高级类型包括字面量类型、联合类型、交叉类型、索引类型、映射类型、条件类型、this类型等。因为内容太多,所以这篇文章先来介绍前三个类型,其余类型会在高级类型的下篇介绍。


系列文章:


一、字面量类型


在 TypeScript 中,字面量不仅可以表示值,还可以表示类型,即所谓的字面量类型。TypeScript 支持 3 种字面量类型:字符串字面量类型、数字字面量类型、布尔字面量类型。对应的字符串字面量、数字字面量、布尔字面量分别拥有与其值一样的字面量类型:


let str: 'hello world' = 'hello world';
let num: 996 = 996;
let bool: true = true
复制代码


1. 字面量类型的使用


(1)字符串字面量

字符串字面量类型其实就是字符串常量,与字符串类型不同的是它是具体的值:

type Name = "TS";
const name1: Name = "test"; // error 不能将类型"test"分配给类型"TS"
const name2: Name = "TS";
复制代码


实际上,定义单个的字面量类型并没有太大用处,它的应用场景是可以把多个字面量类型组合成一个联合类型,用来描述拥有明确成员的实用的集合:

type Direction = "north" | "east" | "south" | "west";
function getDirectionFirstLetter(direction: Direction) {
  return direction.substr(0, 1);
}
getDirectionFirstLetter("test"); // error 类型"test"的参数不能赋给类型“Direction”的参数
getDirectionFirstLetter("east");
复制代码


这里我们使用四个字符串字面量类型组合成了一个联合类型,这样编译器就会检查我们使用的参数是否是指定的字面量类型集合中的成员。通过这种方式,可以将函数的参数限定为更具体的类型。这不仅提升了代码的可读性,还保证了函数的参数类型。


(2)数字字面量

数字字面量类型和字符串字面量类型差不多,都是指定类型为具体的值:

type Age = 18;
interface Info {
  name: string;
  age: Age;
}
const info: Info = {
  name: "TS",
  age: 28 // error 不能将类型“28”分配给类型“18”
};
复制代码


(3)布尔字面量

布尔字面量和上面的两个类似,不在多说:

let success: true
let fail: false
let value: true | false
复制代码


由于布尔值只有true和false两种,所以以下两种类型意思一样的:

let value: true | false
let value: boolean
复制代码


2. 字面量类型的拓宽


在ES6中提出了两个新的声明变量的关键字:let和const,那当他们定义的变量的值相同时,变量的类型是一样的吗?

先来看使用const定义变量的例子:

const str = "hello world";
const num = 996;
const bool = false;
复制代码


这里const定义了三个不能变的常量,在不写类型注解的情况下,TypeScript 会推断出它的类型为赋值字面量的类型。这样就不能再改变变量的值。

再来看使用let定义变量的例子:

let str = "hello world";
let num = 996;
let bool = false;
复制代码


这里没有写注解的变量的类型就变成了赋值字面量类型的父类型,比如str的类型是字符串字面量类型"hello world"的父类型string,num的类型是数字字面量类型996的父类型number,bool的类型是布尔字面量类型false的父类型boolean。这样就意味着,我们可以给这三个变量分别赋值string、number、boolean类型的值:

str = "hello TypeScript";
num = 666;
bool = true;
复制代码


这种将字面量类型转换为其父类型的设计就是字面量类型的拓宽。 通过 let 或 var 定义的变量、函数形参、对象的非只读属性,如果指定了初始值且未显式添加类型注解,那么它们推断出来的类型就是指定的初始值字面量类型拓宽后的类型,这就是字面量类型拓宽。

下面通过一个例子来理解一下字面量类型拓宽:

let str = 'hello'; // 类型是 string
let strFun = (str = 'hello') => str; // 类型是 (str?: string) => string;
const specifiedStr = 'hello'; // 类型是 'this is string'
let str2 = specifiedStr; // 类型是 'string'
let strFun2 = (str = specifiedStr) => str; // 类型是 (str?: string) => string;
复制代码


第一段代码中通过let定义了字符串str,是一个形参,并且没有显式的声明其类型,属于是类型拓宽,所以变量和形参推断出类型为string。


第二段代码中通过const定义了字符串specifiedStr,这个字符串是常量,不能进行修改,所以specifiedStr的类型为hello字面量类型,后面的str2遍历和strFun2函数形参被赋值了字面量类型的常量,并且没有显式的声明其类型,所以变量、形参的类型都被拓宽了,并没有被指定为它对应的字面量类型。这也是符合我们预期的。


二、联合类型


1. 联合类型的使用


如果希望属性为多种类型之一,如字符串或者数组,这时联合类型就派上用场了(它使用 | 作为标记,如 string | number)。**联合类型可以理解为多个类型的并集。**联合类型用来表示变量、参数的类型不是某个单一的类型,而可能是多种不同的类型的组合:


function formatCommandline(command: string[] | string) {
  let line = '';
  if (typeof command === 'string') {
    line = command.trim();
  } else {
    line = command.join(' ').trim();
  }
}
复制代码


联合类型表示一个值可以是几种类型之一,用竖线 | 分隔每个类型,所以 number | string | boolean 表示一个值可以是number、string、boolean类型中的任意一种。

可以使用类型别名抽离联合类型:


type Command = string[] | string
复制代码


2. 类型缩减


说完了联合类型的基本使用,那如果定义的联合类型的包含数字类型和数字字面量类型这种情况,会有什么效果呢?实际上,由于数字类型是数字字面量类型的父类型,所以最后会缩减为数字类型。同样string和boolean在这种情况下也会发生类型缩减。

看下面的例子:


type UnionNum = 1 | number;  // 类型是number
type UniomStr = "string" | string;  // 类型是string
type UnionBool = false | boolean;   // 类型是boolean
复制代码


在这种情况下,TypeScript会对类型进行缩减,将字面量类型去掉,保留原始类型。

但是这样也会造成一个问题:编译器只能提示我们定义的变量是那个原始的类型:

网络异常,图片无法展示
|
不过,TypeScript提供了一种方式来控制类型缩减,只需给父类型添加" & {}"即可:


网络异常,图片无法展示
|
此时,其他字面量类型就不会被缩减,在编辑器中字符串字面量str1、str2等就可以自动提示出来了。


除此之外,当联合类型的成员是接口类型,并满足其中一个接口的属性是另一个接口属性的子集,这个属性也会进行类型缩减:

type UnionInterface = {
  age: "18"
} | {
  age: "18" | "25",
  [key: string]: string;
}
复制代码


由于 "18""18" | "25" 的子集,所以age属性的类型会变成 "18" | "25"。

目录
打赏
0
0
0
0
7
分享
相关文章
TypeScript-内置应用程序类型-Recode
通过使用 `Record` 类型,开发者可以显著提升代码的安全性和可维护性。无论是配置对象、字典结构还是动态表单,`Record` 类型都提供了一个简洁、类型安全的解决方案。
187 82
|
5月前
|
typeScript进阶(9)_type类型别名
本文介绍了TypeScript中类型别名的概念和用法。类型别名使用`type`关键字定义,可以为现有类型起一个新的名字,使代码更加清晰易懂。文章通过具体示例展示了如何定义类型别名以及如何在函数中使用类型别名。
61 1
typeScript进阶(9)_type类型别名
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
88 0
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
5月前
|
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
74 0
|
5月前
|
typeScript进阶(10)_字符串字面量类型
本文介绍了TypeScript中的字符串字面量类型,这种类型用来限制变量只能是某些特定的字符串字面量。通过使用`type`关键字声明,可以确保变量的值限定在预定义的字符串字面量集合中。文章通过示例代码展示了如何声明和使用字符串字面量类型,并说明了它在函数默认参数中的应用。
63 0
TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等
本文深入探讨了TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等,旨在帮助开发者在保证代码质量的同时,实现高效的性能优化,提升用户体验和项目稳定性。
71 6
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
66 2
TypeScript类型声明:基础与进阶
通过本文的介绍,我们详细探讨了TypeScript的基础与进阶类型声明。从基本数据类型到复杂的泛型和高级类型,TypeScript提供了丰富的工具来确保代码的类型安全和可维护性。掌握这些类型声明能够帮助开发者编写更加健壮和高效的代码,提高开发效率和代码质量。希望本文能为您在使用TypeScript时提供实用的参考和指导。
65 2
在 Babel 插件中使用 TypeScript 类型
【10月更文挑战第23天】可以在 Babel 插件中更有效地使用 TypeScript 类型,提高插件的开发效率和质量,减少潜在的类型错误。同时,也有助于提升代码的可理解性和可维护性,使插件的功能更易于扩展和升级。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等