这是昨天的续作.
泛型允许我们编写可重用的组件,并在不同类型之间进行类型安全的操作。
关于此次笔记分析和探讨,我思考了很久,感觉零零散散的,于是便查阅了一些资料.
1. 类中的泛型参数:
```class Container<T> {
private item: T;
constructor(item: T) {
this.item = item;
}
getItem(): T {
return this.item;
}
}
const numberContainer = new Container<number>(42);
const stringContainer = new Container<string>("Hello");
console.log(numberContainer.getItem()); // 输出: 42
console.log(stringContainer.getItem()); // 输出: "Hello"
这个例子表达了,Container 类接受一个泛型参数 T,并将其用作 item 属性的类型和 getItem 方法的返回类型。通过传入不同的类型参数,可以创建具有不同类型的容器实例。
2.泛型函数:
```function printArray<T>(array: T[]): void {
for (let item of array) {
console.log(item);
}
}
const numbers: number[] = [1, 2, 3, 4, 5];
const strings: string[] = ["apple", "banana", "orange"];
printArray(numbers); // 输出: 1 2 3 4 5
printArray(strings); // 输出: "apple" "banana" "orange"
这个泛型函数中 printArray 函数是一个泛型函数,它接受一个数组作为参数,并打印出数组中的每个元素。通过使用泛型参数 T,可以传入不同类型的数组,并保持类型安全。
3.类型约束:
```interface Lengthwise {
length: number;
}
function printLength<T extends Lengthwise>(obj: T): void {
console.log(obj.length);
}
const stringObj = { length: 5, value: "Hello" };
const arrayObj = [1, 2, 3];
printLength(stringObj); // 输出: 5
printLength(arrayObj); // 输出: 3
这个类型约束中,定义了一个接口 Lengthwise,它具有一个 length 属性。然后,使用 extends 关键字将泛型参数 T 约束为实现了 Lengthwise 接口的类型。这样,可以确保传递给 printLength 函数的参数具有 length 属性,从而增加代码的灵活性和安全性。
- 泛型函数和类型约束:
```function mergeArrays<T>(arr1: T[], arr2: T[]): T[] {
return [...arr1, ...arr2];
}
const numbers: number[] = [1, 2, 3];
const strings: string[] = ["apple", "banana", "orange"];
const mergedNumbers: number[] = mergeArrays(numbers, [4, 5, 6]);
const mergedStrings: string[] = mergeArrays(strings, ["grape", "melon"]);
console.log(mergedNumbers); // 输出: [1, 2, 3, 4, 5, 6]
console.log(mergedStrings); // 输出: ["apple", "banana", "orange", "grape", "melon"]
这个例子中,mergeArrays 函数接受两个相同类型的数组,并返回一个合并后的数组。通过使用泛型参数 T,我们可以在函数调用时传入不同类型的数组,而函数内部的逻辑仍然保持类型安全。
5.2. 泛型类和类型约束:
```class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
console.log(numberStack.pop()); // 输出: 3
console.log(numberStack.pop()); // 输出: 2
const stringStack = new Stack<string>();
stringStack.push("apple");
stringStack.push("banana");
stringStack.push("orange");
console.log(stringStack.pop()); // 输出: "orange"
console.log(stringStack.pop()); // 输出: "banana"
其中Stack 类是一个泛型类,可以用于创建不同类型的栈。通过在实例化时指定类型参数,我们可以创建特定类型的栈,并在栈的操作中保持类型安全。
6.泛型接口和类型约束:
```interface Calculator<T> {
add(a: T, b: T): T;
subtract(a: T, b: T): T;
}
const numberCalculator: Calculator<number> = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
},
};
console.log(numberCalculator.add(5, 3)); // 输出: 8
console.log(numberCalculator.subtract(10, 4)); // 输出: 6
const stringCalculator: Calculator<string> = {
add(a, b) {
return `${a} ${b}`;
},
subtract(a, b) {
throw new Error("Operation not supported");
},
};
console.log(stringCalculator.add("Hello", "World")); // 输出: "Hello World"
其中Calculator 接口是一个泛型接口,定义了加法和减法操作。通过在接口实现时指定类型参数,我们可以创建特定类型的计算器,并在操作中保持类型安全。
在学习中,我们应当注意,首先,确保对泛型和类型约束的基本概念有一个清晰的理解。了解什么是泛型,它们如何在函数、类和接口中使用,以及如何使用类型约束来限制泛型参数的行为。TypeScript 的官方文档是学习和理解泛型和类型约束的良好资源。浏览官方文档中关于泛型和类型约束的章节,并尝试运行示例代码来加深理解。尝试编写一些简单的函数、类或接口,使用泛型和类型约束来解决具体问题。通过实际的编码练习,将更深入地理解泛型的使用方法和场景,并更好地掌握类型约束的作用。