TypeScript类与泛型:从入门到实践
引言
作为一名TypeScript初学者,我在学习过程中发现类和泛型是两个既重要又容易混淆的概念。本文将从基础开始,记录我学习TypeScript类和泛型的心得体会,希望能帮助其他初学者更好地理解这些概念。
1. 类的基础使用
首先,让我们从最基本的类开始:
// 一个简单的用户类
class User {
// 类的属性
name: string;
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 类的方法
sayHello() {
console.log(`你好,我是${this.name},今年${this.age}岁`);
}
}
// 使用这个类
const user = new User('小明', 18);
user.sayHello(); // 输出:你好,我是小明,今年18岁
在学习过程中,我发现使用类的几个要点:
- 需要先声明属性,再在构造函数中初始化
- 方法不需要function关键字
- 使用this来访问类的属性和方法
访问修饰符
接下来学习了访问修饰符,这是控制类成员访问权限的方式:
class Student {
public name: string; // 公开的,任何地方都能访问
private score: number; // 私有的,只能在类内部访问
protected grade: string; // 受保护的,只能在类内部和子类中访问
constructor(name: string, score: number, grade: string) {
this.name = name;
this.score = score;
this.grade = grade;
}
// 获取分数的方法
getScore() {
return this.score; // 可以访问私有属性
}
}
2. 初识泛型
刚开始接触泛型时,我觉得很难理解。后来我把它想象成"类型占位符",就容易多了:
// 不使用泛型的数组
const numbers: number[] = [1, 2, 3];
const strings: string[] = ['a', 'b', 'c'];
// 使用泛型的数组
const numbers2: Array<number> = [1, 2, 3];
const strings2: Array<string> = ['a', 'b', 'c'];
一个简单的泛型函数
// 创建一个返回任何传入值的函数
function returnItem<T>(item: T): T {
return item;
}
// 使用这个函数
const numberItem = returnItem<number>(42); // 返回数字
const stringItem = returnItem<string>('hello');// 返回字符串
const booleanItem = returnItem(true); // TypeScript会自动推断类型
这里的<T>就像一个占位符,告诉TypeScript:"这个类型稍后再定"。
3. 实际案例:创建一个简单的购物车
结合类和泛型,我创建了一个简单的购物车示例:
// 商品接口
interface Product {
id: number;
name: string;
price: number;
}
// 购物车类
class ShoppingCart<T extends Product> {
private items: T[] = [];
// 添加商品
addItem(item: T) {
this.items.push(item);
}
// 移除商品
removeItem(id: number) {
this.items = this.items.filter(item => item.id !== id);
}
// 获取所有商品
getItems(): T[] {
return this.items;
}
// 计算总价
getTotalPrice(): number {
return this.items.reduce((total, item) => total + item.price, 0);
}
}
// 使用购物车
const cart = new ShoppingCart<Product>();
cart.addItem({ id: 1, name: '苹果', price: 5 });
cart.addItem({ id: 2, name: '香蕉', price: 3 });
console.log(cart.getTotalPrice()); // 输出:8
4. 学习过程中的困惑与解决
困惑1:泛型约束
最初我不理解为什么需要泛型约束,后来通过这个例子明白了:
// 没有约束的泛型
function printProperty<T>(obj: T, key: string) {
console.log(obj[key]); // 错误:obj可能没有key属性
}
// 使用约束的泛型
function printProperty<T extends { [key: string]: any }>(obj: T, key: string) {
console.log(obj[key]); // 正确:已经确保obj有string类型的键
}
困惑2:类型推断
开始时我总是显式地指定泛型类型,后来学会了让TypeScript自己推断:
// 不需要显式指定类型
const numbers = returnItem(42); // 自动推断为number
const strings = returnItem('hello'); // 自动推断为string
5. 实用小技巧
在学习过程中,我总结了一些有用的技巧:
- 使用接口定义类型:
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T) {
console.log(item.length);
}
logLength('hello'); // 可以用于字符串
logLength([1, 2, 3]); // 可以用于数组
- 默认类型参数:
class Container<T = string> {
value: T;
constructor(value: T) {
this.value = value;
}
}
const stringContainer = new Container('hello'); // T 默认为 string
const numberContainer = new Container<number>(42); // 明确指定 T 为 number
总结
作为初学者,我的学习心得是:
-
循序渐进
- 先掌握类的基础用法
- 理解泛型的概念
- 尝试结合使用类和泛型
-
多动手实践
- 从简单的例子开始
- 逐步增加复杂度
- 解决实际问题
-
常见误区
- 不要过度使用泛型
- 记得添加适当的类型约束
- 善用类型推断
建议:
- 多看官方文档
- 写代码时开启严格模式
- 从简单的项目开始练习
- 遇到问题多查看报错信息
TypeScript的学习是一个渐进的过程,不要期望一下子掌握所有概念。重要的是要多写代码,多实践!