TS入门:泛型
2024年7月24日
泛型
在 TypeScript
中,泛型(Generics)是一种让你在编写代码时能够创建可重用组件的一种工具。泛型提供了一种让代码在类型上更灵活的方法,允许你编写能够处理多种类型的组件,而无需牺牲类型安全性。
为什么使用泛型?
使用泛型的主要原因是为了增强代码的可重用性和类型安全性。例如,考虑一个可以返回数组中第一个元素的函数。如果我们不使用泛型,这个函数只能处理某种特定类型的数据。
泛型的基本语法
类型变量
类型变量,它是一种特殊的变量,只用于表示类型而不是值。
function a<T>(x: T): T {
return x;
}
const b = a<string>('hello world');
泛型函数
泛型的基本语法是在函数、接口或类名后面使用尖括号 <>
,然后在里面定义一个或多个类型类型变量。
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>("myString"); // 你可以显式地传递类型参数
let output2 = identity("myString"); // 或者让编译器推断类型
在这个例子中,identity 函数使用了泛型类型 T,这个类型会在调用函数时被具体类型替换。identity 函数会接收一个类型为 T 的参数,并返回一个类型为 T 的值。
同样的,我们可以把泛型变量T当成是类型的一部分使用,而不是整个类型,看下面的例子:
// 传入一个类型为T的元素组成的数组,并返回由类型为T的元素组成的数组
function identityArr<T>(arg: T[]) T[] {
return arg.sort();
}
// 指定类型T为number
identityArr<number>([2, 1, 4, 6]); // => [1, 2, 4, 6];
定义泛型类型
泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样:
// 定义泛型类型
let output: <T>(arg: T) => T = identity;
let output2: <T>(arg: T[]) => T[] = identityArr;
泛型接口
// 把泛型T当成整个接口的类型参数
interface Fn<T> {
(arg: T): T
}
// 实现Fn接口的函数
function handler<T>(arg: T): T {
return a;
}
// 参数为数字
const f: Fn<number> = handler;
const n: number = f(1);
// 参数为字符串
const s: Fn<string> = handler;
const l: string = s('hello');
TIP
除了泛型接口,我们还可以创建泛型类。 注意,无法创建泛型枚举和泛型命名空间。
泛型类
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
class A<T> {
name: T;
say: (x: T) => T;
}
const a = new A<string>();
a.name = 'yux';
a.say = function(name) {
return name;
};
TIP
类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
泛型约束
有时候你希望泛型只能是某些类型,这时可以使用类型约束。例如,定义一个函数只能处理有 length
属性的对象:
// 定义接口,使用extends约束T
interface Arr {
length: number;
}
function a<T extends Arr>(b: T): T {
return b;
}
const c = a<Arr>({length: 1});
a({ length: 1 }); // OK
a(22); // Error
在泛型约束中使用类型参数
function getObjVal<T, K extends keyof T> (obj: T, key: K): T[K] {
return obj[key];
}
const list = {
name: 'yux',
age: 33,
}
const a = getObjVal(list, 'name'); // OK, => yux
const b = getObjVal(list, 'age'); // OK, => 33
const c = getObjVal(list, 'other'); // Error, Argument of type '"other"' is not assignable to parameter of type '"name" | "age"'.
泛型工具类型
TypeScript 提供了一些实用的泛型工具类型,例如:
Partial<T>
:将类型T
的所有属性变为可选。Readonly<T>
:将类型T
的所有属性变为只读。Record<K, T>
:构造一个对象类型,其键类型为K
,值类型为T
。
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Record<K extends keyof any, T> = {
[P in K]: T;
};
总结
泛型是 TypeScript 中非常强大的特性,它允许你编写更加灵活和可重用的代码,同时保持类型安全性。通过使用泛型,你可以创建适用于多种类型的函数、接口和类,大大提高了代码的可维护性和扩展性。
转载说明
本文允许全文转载,转载请注明来源: 平凡公子 - TS入门:泛型