Skip to content

类型别名

TypeScript 的类型别名是一种为类型起一个新名字的方式,它可以使代码更加易读和可维护。 TS 文档: 类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

语法

只是为类型起了一个新名字,并没有创建新类型。(type 有 = 号)

typescript
type NewName = UnderlyingType;
type A = string;

我们通过 type 关键字声明了一个类型别名 A ,同时它的类型等价于 string 类型。类型别名的作用主要是对一组类型或一个特定类型结构进行封装,以便于在其它地方进行复用。

抽离联合类型

typescript
type ID = number | string;

type count = number | number[];

const hello = (value: count): number => {
  // ...
};

// 抽离联合类型
type StatusCode = 200 | 301 | 400 | 500 | 502;
type PossibleDataTypes = string | number | (() => unknown);

const status: StatusCode = 502;

抽离函数类型

typescript
type Handler = (e: Event) => void;

const clickHandler: Handler = (e) => {};
const moveHandler: Handler = (e) => {};
const dragHandler: Handler = (e) => {};

// 抽离函数声明
type FuncFoo = (name: string) => number;

const foo: FuncFoo = (name) => {
  return name.length;
};

声明对象类型

声明一个对象类型,就像接口那样:

typescript
type ObjType = {
  name: string;
  age: number;
};

工具类型

看起来类型别名真的非常简单,不就是声明了一个变量让类型声明更简洁和易于拆分吗?如果真的只是把它作为类型别名,用来进行特定类型的抽离封装,那的确很简单。然而,类型别名还能作为工具类型。工具类同样基于类型别名,只是多了个泛型

在类型别名中,类型别名可以声明自己能够接受泛型(可以称之为泛型坑位)。一旦接受了泛型,我们就叫它工具类型:

typescript
type Factory<T> = T | number | string;

它的基本功能仍然是创建类型,只不过工具类型能够接受泛型参数,实现更灵活的类型创建功能

工具类型就像一个函数一样,泛型是入参,内部逻辑基于入参进行某些操作,再返回一个新的类型。比如在上面这个工具类型中,我们就简单接受了一个泛型,然后把它作为联合类型的一个成员,返回了这个联合类型

typescript
const foo: Factory<boolean> = true;

我们一般不会直接使用工具类型来做类型标注,而是再度声明一个新的类型别名

typescript
type FactoryWithBool = Factory<boolean>;

const foo: FactoryWithBool = true;

泛型参数的名称(上面的 T )也不是固定的。通常我们使用大写的 T / K / U / V / M / O ...这种形式。如果为了可读性考虑,我们也可以写成大驼峰形式(即在驼峰命名的基础上,首字母也大写)的名称.

typescript
type Factory<NewType> = NewType | number | string;

声明一个简单、有实际意义的工具类型:

typescript
type MaybeNull<T> = T | null;

这个工具类型会接受一个类型,并返回一个包括 null 的联合类型。这样一来,在实际使用时就可以确保你处理了可能为空值的属性读取与方法调用:

typescript
type MaybeNull<T> = T | null;

function process(input: MaybeNull<{ handler: () => {} }>) {
  input?.handler();
}

类似的还有 MaybePromise、MaybeArray。

typescript
type MaybeArray<T> = T | T[];

// 函数泛型
function ensureArray<T>(input: MaybeArray<T>): T[] {
  return Array.isArray(input) ? input : [input];
}

工具类型,主要意义是基于传入的泛型进行各种类型操作,得到一个新的类型。

interface 和 type 区别?

用 interface 描述数据结构,用 type 描述类型关系

定义类型的方式不同

  • type 通过类型别名的方式来给类型一个新名称,可以使用联合类型、元组等;
  • 而 interface 是通过定义对象的形状(shape)来定义类型的。
typescript
// type
type PersonType = { name: string; age: number };

// interface
interface PersonInterface {
  name: string;
  age: number;
}

声明 union 和 tuple

type 更适合于定义 union 和 tuple 类型。

typescript
// union
type UnionType = "foo" | "bar";

// tuple
type TupleType = [string, number];

interface 合并声明

多个同名的interface会自动合并,而多个同名的type是不允许重复定义的。

typescript
// 合并interface
interface Person {
  name: string;
}
interface Person {
  age: number; // 会自动合并到前面的Person
}

// => 相当于合并成这样
interface Person {
  name: string;
  age: number;
}

// type不能重复定义
type Person = {
  // 这里会报错
  name: string;
};

扩展方式不同

type 使用交叉类型(&)实现扩展

typescript
// type extends type
type BasicObject = { a: number; b: string };
type ExtendedObject = BasicObject & { c: boolean; d: string[] };

// ExtendedObject 包含了 BasicObject 的所有属性 a 和 b,
// 以及新增的 c 和 d 属性
let obj: ExtendedObject = {
  a: 1,
  b: "hello",
  c: true,
  d: ["foo", "bar"],
};
typescript
// type extends interface

interface Colorful {
  color: string;
}

type ColoredCircle = Circle & Colorful;
// ColoredCircle 包含了 Circle 和 Colorful 接口的所有成员

// eg2.
interface Name {
  name: string;
}
type User = Name & {
  age: number;
};

interface 使用 extends 实现

typescript
// interface extends interface
interface Name {
  name: string;
}
interface User extends Name {
  age: number;
}

// interface extends type
type Name = {
  name: string;
};
interface User extends Name {
  age: number;
}

其他

  1. type 可以声明基本类型 type Name = string
  2. type 还可以定义字面量联合类型,type x = 'a' | 'b' | 'c' 那么使用该类型只能从这三个值中取,不在的就会报错。
  3. 常用 type 声明联合类型,如函数返回类型是type x = string | object | void,就不用一次次的写,复用性就高了。

TS 中 interface 和 type 究竟有什么区别? - 掘金

小结

  1. type 可以声明基本类型、联合类型、交叉类型、元组,interface 不可以
typescript
type Name = string; // 基本类型

type arrItem = number | string; // 联合类型
const arr: arrItem[] = [1, "2", 3];

type Person = {
  name: Name;
};
type Student = Person & { grade: number }; // 交叉类型

type Teacher = Person & { major: string };

type StudentAndTeacherList = [Student, Teacher]; // 元组类型

const list: StudentAndTeacherList = [
  { name: "lin", grade: 100 },
  { name: "liu", major: "Chinese" },
];
  1. interface 可以合并重复声明,type 不可以