上一篇仅仅是描述了一些基础类型的使用,但是在我们开发时,数据的结构就会很复杂。
这样的话,上一篇的知识好像就不太够用了
下面我们就主要说一下在比较复杂的数据时,我们改如何组合类型
interface、type、enum
基础用法
type Names = string[];
const names: Names = ['shange', 'liu'];
type 如果声明变量的 var、let、const
一样,声明一个存储类型的变量,这个变量就代表赋予它的类型
但要注意的是 type 声明的类型不能更改,在同一作用域下(js 作用域)不能再次使用 type 声明同名称的类型
我们在来介绍两种常在使用 type 时使用的其他两个 ts 关键字 &
和 |
,这两个关键字可以使类型拆分、复用起来
& 符号的作用
咱要用到的类型,先声明
// 组成人体结构的类型
type Foot = {
/** 左脚走路 */
leftWalk: () => void;
/** 右脚走路 */
rightWalk: () => void;
};
type Head = {
/** 嘴 */
mouth: {
/** 说话 */
say(content: string): void;
};
};
正常情况下,我们是这样写的
/** 以对象的结构聚合 */
type PersonStructure = {
head: Head;
foot: Foot;
// 其他部位...
};
但我们为了举栗子,换个写法 (只是为了举栗子)
// 用 & 符号聚合
type PersonStructure = {
head: Head;
} & { foot: Foot };
// 赋值给变量时聚合
const person: { head: Head } & { foot: FooT } = {
head: xxx,
foot: xxx,
};
作用
&
的作用就是将一个类型合并到另外一个类型之中,如同 js
中的 Objact.assign
,将所有的对象聚合在一起后返回
| 符号的作用
/** 普通的蚂蚁 */
type Ant = {
// ... 各种基础类型
};
/** 飞蚁 */
type FlyingAnt = {
name: 'fly';
fly(): void;
} & Ant;
/** 工蚁 */
type WorkerAnt = {
name: 'worker';
move(): void;
} & Ant;
/** 注意,这里使用 | 来枚举变量可能存储值的类型 */
let flyingAnt1: WorkerAnt | FlyingAnt | undefined;
/** 可以整和成一个类型,还是枚举每个类型 */
type MenuAnt = WorkerAnt | FlyingAnt;
let flyingAnt1: MenuAnt | undefined;
// 用一个特定唯一的关键字来确定类型
if (flyingAnt1?.name === 'fly') {
// type: FlyingAnt
flyingAnt1.fly();
}
作用
|
的作用就是枚举这个变量要用到的所有类型,在后续的给变量赋值时,值必须在枚举的列表之中,否则的话,它就会报错
基础用法
interface
常用于声明一个对象形式自定义类型,我们还可以使用 interface 来声明一个可以约束函数属性或类
的自定义类型
声明一个普通自定义类型
interface Person {
name: string;
age: number;
}
const person: Person = {
name: 'shange',
age: 18,
};
声明一个用于约束函数的类型
interface Say {
(content: string): void;
}
const say: Say = content => void 0;
自定义属性的函数
// 还可以在给函数添加一些属性
interface Say {
(content: string): void;
// 要注意,isSay在初始化时一定为undefined,所以这里要用 ?: 或 | undefined 来声明可能为undefined的情况
isSay?: boolean;
// isSay: boolean | undefined;
}
const say: Say = content => void 0;
say.isSay = false;
拥有 this 作用域的函数
interface Say {
// 函数的第一位参数作为this关键字,在解析函数参数时,会自动裁掉
(this: Window, content: string): void;
isSay?: boolean;
}
const say: Say = function () {
this.name;
};
say.isSay = false;
const sayFn = say.bind(window);
interface 使用 extends 揉和多个对象类型
这里我们直接借用 type
中 &
的基础类型,然后用 interface
可用的关键字来揉和类型
// 组成人体结构的类型
type Foot = {
/** 左脚走路 */
leftWalk: () => void;
/** 右脚走路 */
rightWalk: () => void;
};
type Head = {
/** 嘴 */
mouth: {
/** 说话 */
say(content: string): void;
};
};
// 聚合在一起
interface PersonStructure {
foot: Foot;
head: Head;
}
// 继承Structure中的人体结构,extends 的作用和 & 是一样的
interface Person extends PersonStructure {
name: string;
age: number;
}
// extends 还可以继承多个类型,用 `,` 号隔开即可
interface Person extends PersonStructure, A, B, C {}
通常,我们谈起 ts 时,必须了解一个特点,就是 ts 类型只存在与编译前,当转换为 js 时,根据类型来计算代码是否有错误,但转换为 js 后,js 不存在源码中写的类型,但就是有这样的一个 API,它参与了 js 运行时,就是这个 enum
接下来我们先了解下这个 API 的特性
同上,举个栗子
当我们用到颜色时,这个颜色可能还会在多个地方用到,但是又不想重复的写,我们就需要拿一个变量来替代
enum ColorMap {
red = '#ff0000',
blue = '#0000ff',
green = '#00ff00',
// ...
}
// 使用时
el.style.color = ColorMap.red;
enum 会产出一个类型,这个类型所包含的意思就是,这个被赋予这个类型的变量可能是枚举中的某一个
let color: ColorMap = ColorMap.red;
switch (color) {
case ColorMap.red: {
console.log('red');
break;
}
case ColorMap.blue: {
console.log('blue');
break;
}
}
不仅仅是上面的好处
当我们想要改将red
对于的#ff0000
从 16 进制改 rgb 时,我们可以直接改变对于的 value 即可
记住 enum 开发少使用,毕竟会参与运行时,也可以对象来替代
有兴趣可以看以下 ColorMap
在编译成 js 后有什么变化
interface
和 type
大家都需要掌握,enum 知道即可
interface
和 type
都是组合类型和声明一个数据结构的必须要用的变量,那个方便就那个