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"。

相关文章
|
29天前
|
JavaScript 前端开发 Java
TypeScript 类型兼容性
TypeScript 类型兼容性
|
29天前
|
JavaScript 前端开发
typescript 混合类型
typescript 混合类型
|
2天前
|
JavaScript 前端开发 索引
TypeScript 的数组类型
TypeScript 的数组类型
13 1
|
13天前
|
JavaScript 前端开发 IDE
TypeScript中的声明文件(.d.ts):扩展类型系统
TypeScript的`.d.ts`声明文件为JS库提供类型信息,增强IDE支持,如自动完成和类型检查。通过声明合并,可在全局作用域定义类型。示例包括为`my-library`创建声明模块,导出函数和接口。声明文件通常存于`@types`或指定`typeRoots`。用于旧JS代码的类型注解,如`myGlobalObject`。学习更多,参阅TypeScript官方文档。分享你的TS声明文件经验!
|
25天前
|
JavaScript 前端开发 安全
TypeScript:静态类型的动态语言
【6月更文挑战第9天】TypeScript是JavaScript的静态类型超集,解决JS类型安全问题,提供更强的代码组织和维护。它引入静态类型、接口和类,增强类型安全,减少运行时错误。TS与JS无缝集成,兼容现有库和框架,拥有丰富的开发工具和活跃社区。广泛应用在各种规模项目中,尤其提升复杂前端应用的代码质量。学习TypeScript对提升开发效率和代码可靠性极具价值。
28 10
|
23天前
|
前端开发 JavaScript 安全
TypeScript作为一种静态类型的JavaScript超集,其强大的类型系统和面向对象编程特性为微前端架构的实现提供了有力的支持
【6月更文挑战第11天】微前端架构借助TypeScript提升开发效率和代码可靠性。 TypeScript提供类型安全,防止微前端间通信出错;智能提示和自动补全加速跨代码库开发;重构支持简化代码更新。通过定义公共接口确保一致性,用TypeScript编写微前端以保证质量。集成到构建流程确保顺利构建打包。在微前端场景中,TypeScript是强有力的语言选择。
32 2
|
2天前
|
JavaScript 安全
TypeScript(十一)泛型工具类型
TypeScript(十一)泛型工具类型
|
2天前
|
JavaScript 前端开发 编译器
TypeScript(五)类型别名及类型符号
TypeScript(五)类型别名及类型符号
|
2天前
|
JavaScript 前端开发
TypeScript(二)基本类型和特殊类型
TypeScript(二)基本类型和特殊类型
|
7天前
|
JavaScript 安全 开发者
Vue3 中更好地利用 TypeScript 的类型系统来提高代码质量
Vue3 中更好地利用 TypeScript 的类型系统来提高代码质量