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