ts 泛型
TypeScript中的泛型是一种在编写可重用代码时非常有用的功能。它允许类型参数化,这意味着您可以编写可以操作不同类型数据的代码,而无需编写多个函数或类
示例1:基本的泛型函数
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:泛型类
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数组。我们还定义了两个方法:push和pop,它们都操作T类型的数据。最后,我们创建了一个Stack实例,并指定类型参数为number。然后,我们向堆栈推入一些数字,并弹出它们以验证堆栈是正常工作的。
示例3:泛型约束
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>
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类型元素组成的数组。在上面的示例中,我们定义了两个不同类型的数组:numbers和strings。
2. ReadonlyArray<T>
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>
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>
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 泛型:从某个类型中选取指定属性组成一个新的类型。例如:
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 泛型:从某个类型中删除指定属性后得到一个新的类型。例如:
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 泛型:从联合类型中排除某些类型得到一个新的类型。例如:
type MyNumber = number | string;
type NumberOnly = Exclude<MyNumber, string>;
let num: NumberOnly = 42;在这个示例中,使用 Exclude 泛型从联合类型 MyNumber 中排除了 string 类型,创建了一个名为 NumberOnly 的新类型,并使用它定义了一个变量 num。
8. Extract 泛型:从联合类型中提取某些类型得到一个新的类型。例如:
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