<返回目录     Powered by claud/xia兄

第6课: 泛型Generic

什么是泛型?

泛型是一种创建可重用组件的工具,它可以支持多种类型的数据,而不是单一的类型。使用泛型可以创建灵活且类型安全的代码。

泛型函数

// 不使用泛型
function identity(arg: number): number {
  return arg;
}

// 使用泛型
function identity(arg: T): T {
  return arg;
}

// 使用方式1:明确指定类型
let output1 = identity("myString");

// 使用方式2:类型推断
let output2 = identity("myString");

泛型类型

// 泛型函数类型
function identity(arg: T): T {
  return arg;
}

let myIdentity: (arg: T) => T = identity;

// 使用对象字面量形式
let myIdentity2: { (arg: T): T } = identity;

// 使用接口定义
interface GenericIdentityFn {
  (arg: T): T;
}

let myIdentity3: GenericIdentityFn = identity;

泛型类

class GenericNumber {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
  return x + y;
};

let stringNumeric = new GenericNumber();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) {
  return x + y;
};

泛型约束

使用 extends 关键字约束泛型类型:

interface Lengthwise {
  length: number;
}

function loggingIdentity(arg: T): T {
  console.log(arg.length); // 现在可以访问length属性
  return arg;
}

loggingIdentity({ length: 10, value: 3 }); // 正确
loggingIdentity(3); // 错误:number没有length属性

在泛型约束中使用类型参数

function getProperty(obj: T, key: K) {
  return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a"); // 正确
getProperty(x, "m"); // 错误:m不是x的属性

在泛型中使用类类型

class BeeKeeper {
  hasMask: boolean = true;
}

class ZooKeeper {
  nametag: string = "Mikle";
}

class Animal {
  numLegs: number = 4;
}

class Bee extends Animal {
  keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
  keeper: ZooKeeper = new ZooKeeper();
}

function createInstance(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;

泛型工具类型

// Partial - 将所有属性变为可选
interface Todo {
  title: string;
  description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial) {
  return { ...todo, ...fieldsToUpdate };
}

// Readonly - 将所有属性变为只读
const todo: Readonly = {
  title: "Delete inactive users",
  description: "Clean up database"
};

todo.title = "Hello"; // 错误:只读属性

// Record - 创建键值对类型
type PageInfo = {
  title: string;
};

type Page = "home" | "about" | "contact";

const nav: Record = {
  home: { title: "Home" },
  about: { title: "About" },
  contact: { title: "Contact" }
};

多个类型参数

function pair(first: T, second: U): [T, U] {
  return [first, second];
}

let result = pair("age", 25);
let result2 = pair("name", "Alice"); // 类型推断
泛型的优势:
  • 代码重用性:一次编写,多种类型使用
  • 类型安全:编译时检查类型错误
  • 更好的IDE支持:自动补全和类型提示
练习:
  1. 创建一个泛型函数,返回数组的第一个元素
  2. 实现一个泛型类Stack,支持push和pop操作
  3. 创建一个泛型函数,交换元组中的两个元素
  4. 使用泛型约束创建一个函数,只接受有length属性的参数