返回

类型系统中的泛型化方略:从 TypeScript 学习泛型编程的精髓

前端

基础必备知识

联合类型 vs 交叉类型

联合类型使用 “|”表示或的关系,满足其中的一个情况即可。

type User = {
  name: string;
};

type Admin = {
  name: string;
  role: string;
};

type UserOrAdmin = User | Admin;

let userOrAdmin: UserOrAdmin = {
  name: 'John',
};

// userOrAdmin 可以是 UserAdmin 类型
console.log(userOrAdmin.name); // John

交叉类型使用“&”表示与的关系,必须满足所有情况。

type UserWithAdmin = User & Admin;

let userWithAdmin: UserWithAdmin = {
  name: 'John',
  role: 'admin',
};

// userWithAdmin 必须同时具有 UserAdmin 的属性
console.log(userWithAdmin.name); // John
console.log(userWithAdmin.role); // admin

类型别名

类型别名可以让我们给一个类型起一个新的名字,使代码更加简洁和易读。

type StringOrNumber = string | number;

let stringOrNumber: StringOrNumber = 'Hello';

// stringOrNumber 可以是 string 或 number 类型
console.log(stringOrNumber); // Hello

类型参数

类型参数允许我们在定义函数或类时使用泛型类型。类型参数用尖括号 <> 表示,放在函数或类名的后面。

function identity<T>(value: T): T {
  return value;
}

let numberIdentity: number = identity(10);

// numberIdentity 的类型是 number
console.log(numberIdentity); // 10

let stringIdentity: string = identity('Hello');

// stringIdentity 的类型是 string
console.log(stringIdentity); // Hello

约束

约束可以限制泛型类型的范围,确保泛型类型满足某些条件。约束使用 extends 表示。

function getProperty<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

let name = getProperty({ name: 'John' }, 'name');

// name 的类型是 string
console.log(name); // John

推断

TypeScript 可以推断泛型类型的具体类型,这使得代码更加简洁和易于维护。

function swap<T>(a: T, b: T): [T, T] {
  return [b, a];
}

let [first, second] = swap(1, 2);

// first 的类型是 number
console.log(first); // 2

// second 的类型是 number
console.log(second); // 1

案例

泛型编程在 TypeScript 中有很多应用场景,以下是一些常见的案例:

  • 集合:泛型可以用于定义集合类型,如数组、链表、栈等。
  • 算法:泛型可以用于定义算法,如排序、搜索、遍历等。
  • 函数式编程:泛型可以用于定义高阶函数,如 map、filter、reduce 等。
  • 组件:泛型可以用于定义可重用的组件,如 React 组件、Angular 组件等。

总结

泛型编程是 TypeScript 中一项强大的特性,它允许我们在代码中定义通用的类型,这些类型可以适用于不同类型的数据。泛型编程可以使代码更加简洁、易读和可维护。通过学习 TypeScript 中的泛型,我们可以理解泛型编程的精髓,并将其应用到我们的代码中。