Skip to content
On this page

ts 泛型

TypeScript 中的泛型是一种在编写可重用代码时非常有用的功能。它允许类型参数化,这意味着您可以编写可以操作不同类型数据的代码,而无需编写多个函数或类

示例1:基本的泛型函数

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

let output = identity<string>("hello world");
console.log(output);

在上面的示例中,我们定义了一个泛型函数identity,它接受一个类型参数T和一个参数arg,并返回arg。通过使用<T>语法,我们告诉TypeScript该函数是泛型的。然后,我们可以使用T来表示任何类型。

示例2:泛型类

typescript
class Stack<T> {
  private items: T[] = [];

  push(item: T) {
    this.items.push(item);
  }

  pop() {
    return this.items.pop();
  }
}

const stack = new Stack<number>();
stack.push(1);
stack.push(2);
stack.push(3);

console.log(stack.pop()); // 3
console.log(stack.pop()); // 2
console.log(stack.pop()); // 1

在上面的示例中,我们定义了一个泛型类Stack,它接受一个类型参数T并拥有一个私有成员items,其类型为T数组。我们还定义了两个方法:pushpop,它们都操作T类型的数据。最后,我们创建了一个Stack实例,并指定类型参数为number。然后,我们向堆栈推入一些数字,并弹出它们以验证堆栈是正常工作的。

示例3:泛型约束

typescript
interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(arg: T) {
  console.log(arg.length);
}

logLength("hello world"); // 11
logLength([1, 2, 3]); // 3

在上面的示例中,我们定义了一个接口HasLength,该接口包含一个length属性。然后,我们定义了一个函数logLength,其类型参数T被限制为实现了HasLength接口的类型。在函数体内,我们可以安全地访问arg.length属性,因为它已经被证明存在于T类型中。最后,我们调用了logLength函数并传递了两个具有不同长度属性的参数(字符串和数组)。

内置泛型

TypeScript 提供了许多内置的泛型类型和接口,这些类型可以帮助我们在编写代码时更轻松地处理各种数据类型。以下是一些常用的内置泛型类型:

1. Array<T>

typescript
const numbers: Array<number> = [1, 2, 3, 4, 5];
const strings: Array<string> = ["hello", "world"];

console.log(numbers); // [1, 2, 3, 4, 5]
console.log(strings); // ["hello", "world"]

Array<T>表示一个由T类型元素组成的数组。在上面的示例中,我们定义了两个不同类型的数组:numbersstrings

2. ReadonlyArray<T>

typescript
const numbers: ReadonlyArray<number> = [1, 2, 3, 4, 5];
// numbers.push(6); // compile error

console.log(numbers); // [1, 2, 3, 4, 5]

ReadonlyArray<T>表示一个只读的由T类型元素组成的数组。在上面的示例中,我们定义了一个只读的数字数组numbers。由于它是只读的,我们不能使用push()等方法改变它的内容。

3. Partial<T>

typescript
interface Person {
  name: string;
  age: number;
}

function updatePerson(person: Person, propsToUpdate: Partial<Person>) {
  return { ...person, ...propsToUpdate };
}

const john: Person = { name: "John", age: 30 };
const updatedJohn = updatePerson(john, { age: 31 });

console.log(updatedJohn); // { name: "John", age: 31 }

Partial<T>表示一个T类型的对象,其中所有属性都是可选的。在上面的示例中,我们定义了一个Person接口和一个updatePerson函数,它接受一个Person参数和一个部分Person参数(即只包含Person一部分属性)。然后,我们使用扩展运算符将这两个参数合并为一个新的对象,并返回它。

4. Record<K, T>

typescript
const users: Record<string, { name: string }> = {
  john: { name: "John" },
  jane: { name: "Jane" },
};

console.log(users["john"]); // { name: "John" }

Record<K, T>表示一个由K类型键和T类型值组成的对象。在上面的示例中,我们定义了一个名为users的对象,其中键是字符串类型,值是包含name属性的对象类型。然后,我们使用users["john"]语法来访问john用户的数据。

5.Pick 泛型:从某个类型中选取指定属性组成一个新的类型。例如:

ts
interface Person {
  name: string;
  age: number;
  address: string;
}

type PersonNameOnly = Pick<Person, 'name'>;

let person: PersonNameOnly = { name: 'Tom' };

在这个示例中,使用 Pick 泛型从 Person 类型中选取了 name 属性,创建了一个名为 PersonNameOnly 的新类型,并使用它定义了一个变量 person

6. Omit 泛型:从某个类型中删除指定属性后得到一个新的类型。例如:

ts
interface Person {
  name: string;
  age: number;
  address: string;
}

type PersonWithoutAddress = Omit<Person, 'address'>;

let person: PersonWithoutAddress = { name: 'Tom', age: 30 };

在这个示例中,使用 Omit 泛型从 Person 类型中删除了 address 属性,创建了一个名为 PersonWithoutAddress 的新类型,并使用它定义了一个变量 person

7. Exclude 泛型:从联合类型中排除某些类型得到一个新的类型。例如:

ts
type MyNumber = number | string;
type NumberOnly = Exclude<MyNumber, string>;

let num: NumberOnly = 42;

在这个示例中,使用 Exclude 泛型从联合类型 MyNumber 中排除了 string 类型,创建了一个名为 NumberOnly 的新类型,并使用它定义了一个变量 num

8. Extract 泛型:从联合类型中提取某些类型得到一个新的类型。例如:

ts
type MyNumber = number | string;
type NumberOnly = Extract<MyNumber, number>;

let num: NumberOnly = 42;

在这个示例中,使用 Extract 泛型从联合类型 MyNumber 中提取了 number 类型,创建了一个名为 NumberOnly 的新类型,并使用它定义了一个变量 num

还有其他许多内置的泛型类型和接口,可以去官网查看具体用法:https://www.typescriptlang.org/docs/handbook/utility-types.html

Released under the MIT License.