实践目标
- 聚焦于 TypeScript 中的 类 和 泛型 的使用,
- 理解 TypeScript 中泛型的基本概念。
- 学习如何结合类使用泛型。
- 通过实际案例演示泛型在增加代码灵活性和安全性方面的作用。
- 使用类型约束(
extends)对泛型进行限制。
项目内容
选题方向
设计一个小型项目,例如 "通用数据存储类" 或 "自定义列表操作类" 。通过实现:
- 一个支持多种数据类型的存储类。
- 泛型约束确保数据类型一致性和安全性。
- 代码示例展示灵活性和实际场景应用。
项目实现
1. 创建一个泛型类
实现一个 Storage<T> 类,用于存储任意类型的数据。
class DataStorage<T> {
private items: T[] = [];
addItem(item: T): void {
this.items.push(item);
}
getAllItems(): T[] {
return this.items;
}
removeItem(index: number): void {
if (index >= 0 && index < this.items.length) {
this.items.splice(index, 1);
} else {
console.error('Invalid index');
}
}
}
// 示例
const stringStorage = new DataStorage<string>();
stringStorage.addItem('Hello');
console.log(stringStorage.getAllItems()); // 输出: ['Hello']
运行结果
2. 使用泛型类
展示如何使用 Storage<T> 类存储不同类型的数据。
// 存储字符串
const stringStorage = new Storage<string>();
stringStorage.addItem('Hello');
stringStorage.addItem('World');
console.log(stringStorage.getAllItems()); // 输出: ['Hello', 'World']
// 存储数字
const numberStorage = new Storage<number>();
numberStorage.addItem(42);
numberStorage.addItem(99);
console.log(numberStorage.getAllItems()); // 输出: [42, 99]
// 存储对象
type User = { id: number; name: string };
const userStorage = new Storage<User>();
userStorage.addItem({ id: 1, name: 'Alice' });
userStorage.addItem({ id: 2, name: 'Bob' });
console.log(userStorage.getAllItems());
// 输出: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
运行结果
3. 添加类型约束
通过 extends 对泛型参数添加约束,确保类型符合预期。例如,限制泛型类型必须是具有 id 属性的对象。
interface HasId {
id: number;
}
class IdStorage<T extends HasId> {
private items: T[] = [];
addItem(item: T): void {
this.items.push(item);
}
getItemById(id: number): T | undefined {
return this.items.find(item => item.id === id);
}
getAllItems(): T[] {
return this.items;
}
}
// 使用带约束的泛型类
const idStorage = new IdStorage<{ id: number; name: string }>();
idStorage.addItem({ id: 1, name: 'Alice' });
idStorage.addItem({ id: 2, name: 'Bob' });
console.log(idStorage.getItemById(1)); // 输出: { id: 1, name: 'Alice' }
console.log(idStorage.getAllItems());
// 输出: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
运行结果
4. 综合案例:缓存系统
创建一个缓存系统类,存储带有过期时间的数据。
interface CacheItem<T> {
data: T;
expiry: Date;
}
class Cache<T> {
private cache: Map<string, CacheItem<T>> = new Map();
set(key: string, data: T, ttl: number): void {
const expiry = new Date(Date.now() + ttl);
this.cache.set(key, { data, expiry });
}
get(key: string): T | undefined {
const item = this.cache.get(key);
if (!item) return undefined;
if (item.expiry > new Date()) {
return item.data;
} else {
this.cache.delete(key); // 删除过期缓存
return undefined;
}
}
delete(key: string): void {
this.cache.delete(key);
}
}
// 使用缓存系统
const cache = new Cache<number>();
cache.set('pi', 3.14159, 5000); // 缓存 5 秒
console.log(cache.get('pi')); // 输出: 3.14159
setTimeout(() => console.log(cache.get('pi')), 6000); // 输出: undefined (过期)
运行结果
总结
- 灵活性:通过泛型,
Storage<T>类可以存储任何类型的数据,而无需为每种类型单独创建类。 - 安全性:使用类型约束(如
T extends HasId),保证了类型的准确性。 - 扩展性:可以轻松地为泛型类添加新方法,如
Cache<T>中的过期处理逻辑。 - 实际应用场景:泛型在存储系统、工具类(如队列、栈)、缓存系统等场景中尤为常见。