TypeScript 类使用完全指南
TypeScript 类使用完全指南
目录
基础概念
类型系统
面向对象特性
高级特性
工程实践
基础概念
基础语法
TypeScript 类的基本语法结构和核心概念。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(): void {
console.log(`Hello, I'm ${this.name}`);
}
}
const person = new Person('Alice', 25);
person.sayHello(); // 输出: Hello, I'm Alice
类成员修饰符
TypeScript 提供了多种类成员修饰符,用于控制类成员的行为和特性。
1. static(静态成员)
静态成员属于类本身而不是类的实例,可以通过类名直接访问。
class MathHelper {
// 静态属性
static readonly PI = 3.14159;
private static counter = 0;
// 静态方法
static add(x: number, y: number): number {
return x + y;
}
// 静态方法可以访问其他静态成员
static getNextId(): number {
return ++MathHelper.counter;
}
}
2. readonly(只读属性)
readonly 修饰符使属性只能在声明时或构造函数中赋值。
class Configuration {
readonly apiKey: string;
static readonly VERSION = '1.0.0';
constructor(apiKey: string) {
this.apiKey = apiKey; // 只能在构造函数中赋值
}
}
3. abstract(抽象成员)
abstract 用于定义抽象类和抽象成员。
abstract class Shape {
abstract readonly name: string;
abstract calculateArea(): number;
}
访问修饰符
TypeScript 提供了三种访问修饰符:
1. public(默认)
class PublicExample {
public name: string;
age: number; // 隐式 public
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
2. private
class PrivateExample {
#internalId: string; // ECMAScript 私有字段
private secretKey: string; // TypeScript private
constructor(key: string) {
this.#internalId = `id_${Date.now()}`;
this.secretKey = key;
}
}
3. protected
class ProtectedExample {
protected baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
}
构造函数
构造函数用于初始化类的实例。
class User {
// 参数属性语法
constructor(
public name: string,
private age: number,
protected id: string
) {}
// 构造函数重载
static create(name: string): User;
static create(config: { name: string; age: number }): User;
static create(nameOrConfig: string | { name: string; age: number }): User {
if (typeof nameOrConfig === 'string') {
return new User(nameOrConfig, 0, 'default');
} else {
return new User(nameOrConfig.name, nameOrConfig.age, 'default');
}
}
}
属性与方法
类的属性和方法定义了类的数据和行为。
class Product {
// 属性
name: string;
price: number;
readonly id: string;
// 可选属性
description?: string;
// 方法
constructor(name: string, price: number) {
this.name = name;
this.price = price;
this.id = Math.random().toString(36).substr(2, 9);
}
// 实例方法
getFormattedPrice(): string {
return `$${this.price.toFixed(2)}`;
}
// 方法重载
update(name: string): void;
update(price: number): void;
update(nameOrPrice: string | number): void {
if (typeof nameOrPrice === 'string') {
this.name = nameOrPrice;
} else {
this.price = nameOrPrice;
}
}
}
访问修饰符
TypeScript 提供了三种访问修饰符来控制类成员的可访问性:
1. public(默认)
- 如果不指定修饰符,默认就是 public
- 可以在任何地方被访问(类内部、子类、实例)
- 适用于需要对外暴露的 API 和公共接口
class PublicExample {
public name: string; // 显式声明 public
age: number; // 隐式 public
constructor(name: string, age: number) {
this.name = name; // 可以在类内部访问
this.age = age;
}
}
const example = new PublicExample('Alice', 25);
console.log(example.name); // 可以在类外部访问
console.log(example.age); // 可以在类外部访问
2. private
- 只能在声明的类内部访问
- 子类和实例都不能直接访问
- 使用
#
符号(ECMAScript 私有字段)或private
关键字 - 适用于类的内部实现细节
class PrivateExample {
#internalId: string; // ECMAScript 私有字段
private secretKey: string; // TypeScript private
constructor(key: string) {
this.#internalId = `id_${Date.now()}`;
this.secretKey = key;
}
}
3. protected
- 可以在声明的类和其子类中访问
- 实例不能直接访问
- 适用于需要在继承链中共享的属性和方法
class ProtectedExample {
protected baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
}
4. 修饰符的组合使用
修饰符可以与其他关键字组合使用:
class ModifierCombination {
// readonly:只读属性
public readonly id: string;
protected readonly createdAt: Date;
private readonly secret: string;
// static:静态成员
public static readonly VERSION = '1.0.0';
protected static readonly API_KEY = 'xxx';
private static readonly INTERNAL_CONFIG = {};
// abstract:抽象成员
protected abstract readonly type: string;
protected abstract validate(): boolean;
constructor(id: string, secret: string) {
this.id = id; // 只能在构造函数中赋值
this.createdAt = new Date();
this.secret = secret;
}
}
5. 访问修饰符的最佳实践
封装原则
- 默认使用 private,除非确实需要对外暴露
- 通过公共方法控制对私有成员的访问
- 使用 protected 而不是 public 来共享需要继承的功能
命名约定
- 私有成员使用下划线前缀(虽然不是必需的)
- 使用描述性名称表明可见性意图
安全性考虑
- 使用 ECMAScript 私有字段(#)提供运行时私有性保证
- TypeScript 的 private 只提供编译时检查
- 敏感数据应该始终使用私有修饰符
接口设计
- 公共 API 应该是最小必要集
- 使用 protected 创建稳定的继承接口
- 使用私有成员隐藏实现细节
class BestPractices {
// 私有成员使用下划线前缀
private _state: string;
#sensitiveData: string;
// 受保护的成员用于继承
protected abstract validateState(state: string): boolean;
// 公共 API 保持最小化
public setState(newState: string) {
if (this.validateState(newState)) {
this._state = newState;
}
}
// 工厂方法模式示例
protected abstract createInstance(): BestPractices;
public static create(): BestPractices {
const instance = new this();
return instance.createInstance();
}
}
构造函数
基本构造函数
class Point {
constructor(
public x: number,
public y: number
) {
// TypeScript 的参数属性语法,自动创建并初始化成员变量
}
}
多构造函数重载
class DateFormatter {
constructor(format: string);
constructor(options: { format: string; timezone: string });
constructor(formatOrOptions: string | { format: string; timezone: string }) {
// 实现构造函数
}
}
属性与方法
只读属性
class Circle {
readonly PI: number = 3.14159;
readonly radius: number;
constructor(radius: number) {
this.radius = radius; // 只能在构造函数中赋值
}
}
可选属性
class UserProfile {
name: string;
age?: number; // 可选属性
bio?: string; // 可选属性
constructor(name: string) {
this.name = name;
}
}
方法重载
class Calculator {
add(a: number, b: number): number;
add(a: string, b: string): string;
add(a: any, b: any): any {
return a + b;
}
}
继承
基本继承
class Animal {
constructor(protected name: string) {}
makeSound(): void {
console.log('Some sound');
}
}
class Dog extends Animal {
constructor(
name: string,
private breed: string
) {
super(name);
}
makeSound(): void {
console.log('Woof!');
}
getInfo(): string {
return `${this.name} is a ${this.breed}`; // 可以访问 protected name
}
}
多重继承(通过接口)
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
class Duck extends Animal implements Flyable, Swimmable {
fly(): void {
console.log('Flying...');
}
swim(): void {
console.log('Swimming...');
}
}
抽象类
abstract class Shape {
abstract getArea(): number; // 抽象方法必须在派生类中实现
printArea(): void {
// 具体方法可以包含实现
console.log(`Area: ${this.getArea()}`);
}
}
class Square extends Shape {
constructor(private side: number) {
super();
}
getArea(): number {
return this.side * this.side;
}
}
接口实现
interface Printable {
print(): void;
getContent(): string;
}
class Document implements Printable {
constructor(private content: string) {}
print(): void {
console.log(this.getContent());
}
getContent(): string {
return this.content;
}
}
静态成员
class MathUtils {
static readonly PI: number = 3.14159;
static add(x: number, y: number): number {
return x + y;
}
static {
// 静态初始化块(TypeScript 4.4+)
console.log('Class initialized');
}
}
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.add(5, 3)); // 8
Getter 和 Setter
TypeScript 中的 getter 和 setter 允许你拦截对类属性的访问和修改,提供了一种控制属性读写的方式。
1. 基本用法
getter 和 setter 可以用来:
- 验证属性值
- 转换属性值
- 计算派生值
- 触发副作用
- 实现懒加载
class User {
private _name: string;
private _age: number;
// 基本的 getter 和 setter
get name(): string {
return this._name;
}
set name(value: string) {
if (!value) {
throw new Error('Name cannot be empty');
}
this._name = value.trim();
}
// 带验证的 setter
get age(): number {
return this._age;
}
set age(value: number) {
if (value < 0 || value > 150) {
throw new Error('Age must be between 0 and 150');
}
this._age = value;
}
}
const user = new User();
user.name = 'John Doe'; // 设置值
console.log(user.name); // 获取值
user.age = 25; // 有效
// user.age = -1; // 抛出错误
2. 计算属性
使用 getter 实现计算属性,可以根据其他属性动态计算值:
class Circle {
constructor(private _radius: number) {}
get radius(): number {
return this._radius;
}
set radius(value: number) {
if (value < 0) {
throw new Error('Radius cannot be negative');
}
this._radius = value;
}
// 计算属性
get diameter(): number {
return this._radius * 2;
}
get area(): number {
return Math.PI * this._radius ** 2;
}
get circumference(): number {
return 2 * Math.PI * this._radius;
}
}
const circle = new Circle(5);
console.log(circle.diameter); // 10
console.log(circle.area); // 78.54...
console.log(circle.circumference); // 31.42...
3. 懒加载
使用 getter 实现属性的懒加载:
class ExpensiveData {
private _data: number[] | null = null;
// 懒加载属性
get data(): number[] {
if (this._data === null) {
// 首次访问时才加载数据
console.log('Loading data...');
this._data = this.loadData();
}
return this._data;
}
private loadData(): number[] {
// 模拟耗时操作
return Array.from({ length: 1000 }, (_, i) => i);
}
}
const expensiveData = new ExpensiveData();
// 数据只在首次访问时加载
console.log(expensiveData.data.length); // 输出: Loading data... 1000
console.log(expensiveData.data.length); // 输出: 1000(不会再次加载)
4. 访问控制和验证
使用 getter 和 setter 实现属性访问控制和验证:
class BankAccount {
private _balance: number = 0;
private _transactions: number[] = [];
// 只读属性
get balance(): number {
return this._balance;
}
// 只读属性,返回副本防止修改
get transactions(): number[] {
return [...this._transactions];
}
// 验证存款金额
deposit(amount: number): void {
if (amount <= 0) {
throw new Error('Deposit amount must be positive');
}
this._balance += amount;
this._transactions.push(amount);
}
// 验证取款金额
withdraw(amount: number): void {
if (amount <= 0) {
throw new Error('Withdrawal amount must be positive');
}
if (amount > this._balance) {
throw new Error('Insufficient funds');
}
this._balance -= amount;
this._transactions.push(-amount);
}
}
5. 类型转换和格式化
使用 getter 和 setter 实现值的转换和格式化:
class Product {
private _price: number = 0;
private _name: string = '';
get price(): number {
return this._price;
}
set price(value: number) {
// 保留两位小数
this._price = Math.round(value * 100) / 100;
}
// 格式化价格显示
get formattedPrice(): string {
return `$${this._price.toFixed(2)}`;
}
get name(): string {
return this._name;
}
set name(value: string) {
// 转换为标题格式
this._name = value
.split(' ')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ');
}
}
const product = new Product();
product.price = 19.999;
console.log(product.price); // 20
console.log(product.formattedPrice); // $20.00
product.name = 'gaming LAPTOP';
console.log(product.name); // Gaming Laptop
6. 状态管理和副作用
使用 getter 和 setter 管理状态变化和触发副作用:
type Observer = () => void;
class StateManager {
private _state: Record<string, any> = {};
private _observers: Observer[] = [];
// 代理所有状态访问
get state(): Readonly<Record<string, any>> {
return { ...this._state };
}
// 设置单个状态
setState(key: string, value: any): void {
const oldValue = this._state[key];
if (oldValue !== value) {
this._state[key] = value;
this.notifyObservers();
}
}
// 批量更新状态
setMultipleStates(updates: Record<string, any>): void {
let hasChanges = false;
for (const [key, value] of Object.entries(updates)) {
if (this._state[key] !== value) {
this._state[key] = value;
hasChanges = true;
}
}
if (hasChanges) {
this.notifyObservers();
}
}
// 观察者模式
addObserver(observer: Observer): void {
this._observers.push(observer);
}
private notifyObservers(): void {
this._observers.forEach((observer) => observer());
}
}
// 使用示例
const stateManager = new StateManager();
stateManager.addObserver(() => console.log('State changed:', stateManager.state));
stateManager.setState('user', { name: 'John' });
stateManager.setMultipleStates({
theme: 'dark',
language: 'en',
});
7. 最佳实践
命名约定:
- 私有属性使用下划线前缀
- getter/setter 使用相同的名称(不带下划线)
- 只读属性可以直接使用 public readonly
性能考虑:
- getter 应该是轻量级的
- 避免在 getter 中进行耗时操作
- 考虑使用缓存机制
设计原则:
- 保持 getter/setter 的简单性
- 避免在 setter 中触发复杂的副作用
- 使用 readonly 替代只有 getter 的属性
错误处理:
- 在 setter 中进行输入验证
- 提供清晰的错误信息
- 考虑使用自定义错误类型
class PropertyError extends Error {
constructor(
public propertyName: string,
public value: any,
message: string
) {
super(`Invalid value for ${propertyName}: ${message}`);
this.name = 'PropertyError';
}
}
class Person {
private _age: number = 0;
get age(): number {
return this._age;
}
set age(value: number) {
if (typeof value !== 'number') {
throw new PropertyError('age', value, 'Age must be a number');
}
if (value < 0 || value > 150) {
throw new PropertyError('age', value, 'Age must be between 0 and 150');
}
this._age = value;
}
}
装饰器
注意:装饰器是实验性特性,需要在 tsconfig.json 中启用。
// 类装饰器
function logger<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
console.log('Instance created');
}
};
}
// 方法装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with:`, args);
return originalMethod.apply(this, args);
};
return descriptor;
}
// 属性装饰器
function required(target: any, propertyKey: string) {
let value: any;
const getter = () => value;
const setter = (newVal: any) => {
if (newVal === undefined || newVal === null) {
throw new Error(`${propertyKey} is required`);
}
value = newVal;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
}
@logger
class Example {
@required
name: string;
@log
greet(message: string): void {
console.log(`${this.name} says: ${message}`);
}
}
高级模式
TypeScript 类支持多种高级设计模式,这些模式可以帮助我们构建更加健壮和可维护的代码。
1. 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供对该实例的全局访问点。
使用场景:
- 全局状态管理
- 配置管理
- 数据库连接池
- 日志记录器
class Singleton {
private static instance: Singleton;
private constructor(private config: Record<string, any> = {}) {}
static getInstance(config?: Record<string, any>): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton(config);
}
return Singleton.instance;
}
// 线程安全的双重检查锁定模式
static getInstanceThreadSafe(config?: Record<string, any>): Singleton {
if (!Singleton.instance) {
// 在实际场景中,这里应该有适当的锁定机制
if (!Singleton.instance) {
Singleton.instance = new Singleton(config);
}
}
return Singleton.instance;
}
getConfig(): Record<string, any> {
return { ...this.config };
}
}
// 使用示例
const instance1 = Singleton.getInstance({ env: 'dev' });
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. 工厂模式(Factory Pattern)
工厂模式提供了创建对象的接口,让子类决定实例化哪个类。
使用场景:
- 对象创建的封装
- 依赖注入
- 平台特定实现
- 插件系统
// 产品接口
interface Animal {
makeSound(): void;
getType(): string;
}
// 具体产品
class Dog implements Animal {
makeSound(): void {
console.log('Woof!');
}
getType(): string {
return 'Dog';
}
}
class Cat implements Animal {
makeSound(): void {
console.log('Meow!');
}
getType(): string {
return 'Cat';
}
}
// 抽象工厂
abstract class AnimalFactory {
abstract createAnimal(): Animal;
// 工厂方法
static createAnimalFactory(type: string): AnimalFactory {
switch (type.toLowerCase()) {
case 'dog':
return new DogFactory();
case 'cat':
return new CatFactory();
default:
throw new Error(`Unknown animal type: ${type}`);
}
}
}
// 具体工厂
class DogFactory extends AnimalFactory {
createAnimal(): Animal {
return new Dog();
}
}
class CatFactory extends AnimalFactory {
createAnimal(): Animal {
return new Cat();
}
}
// 使用示例
const dogFactory = AnimalFactory.createAnimalFactory('dog');
const dog = dogFactory.createAnimal();
dog.makeSound(); // 输出: Woof!
3. Mixin 模式(Mixin Pattern)
Mixin 模式允许将行为注入到类中,实现代码重用和功能组合。
使用场景:
- 跨类共享行为
- 实现多重继承
- 装饰器模式的替代方案
- 功能模块化
// 定义 Mixin 类型
type Constructor<T = {}> = new (...args: any[]) => T;
// Mixin 函数
function Timestamped<TBase extends Constructor>(Base: TBase) {
return class extends Base {
timestamp = new Date();
getTimestamp(): Date {
return this.timestamp;
}
};
}
function Activatable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
isActive = false;
activate(): void {
this.isActive = true;
}
deactivate(): void {
this.isActive = false;
}
};
}
// 基础类
class User {
constructor(public name: string) {}
}
// 应用 Mixins
const TimestampedUser = Timestamped(User);
const TimestampedActivatableUser = Activatable(TimestampedUser);
// 使用示例
const user = new TimestampedActivatableUser('John');
console.log(user.getTimestamp());
user.activate();
console.log(user.isActive); // true
4. 代理模式(Proxy Pattern)
代理模式为其他对象提供一个代理以控制对这个对象的访问。
使用场景:
- 延迟加载
- 访问控制
- 日志记录
- 缓存实现
// 目标接口
interface IService {
getData(): Promise<string>;
}
// 实际服务
class RealService implements IService {
async getData(): Promise<string> {
// 模拟耗时操作
await new Promise((resolve) => setTimeout(resolve, 1000));
return 'Real service data';
}
}
// 代理类
class ServiceProxy implements IService {
private realService: RealService | null = null;
private cache: string | null = null;
async getData(): Promise<string> {
// 缓存检查
if (this.cache) {
console.log('Returning cached data');
return this.cache;
}
// 延迟初始化
if (!this.realService) {
console.log('Creating real service');
this.realService = new RealService();
}
// 获取数据并缓存
console.log('Fetching fresh data');
this.cache = await this.realService.getData();
return this.cache;
}
clearCache(): void {
this.cache = null;
}
}
// 使用示例
async function demo() {
const proxy = new ServiceProxy();
console.log(await proxy.getData()); // 首次调用,创建服务并获取数据
console.log(await proxy.getData()); // 使用缓存数据
proxy.clearCache();
console.log(await proxy.getData()); // 重新获取数据
}
5. 观察者模式(Observer Pattern)
观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知。
使用场景:
- 事件处理系统
- 状态同步
- UI 更新
- 消息推送
interface Observer {
update(data: any): void;
}
class Subject {
private observers: Observer[] = [];
private state: any;
attach(observer: Observer): void {
const isExist = this.observers.includes(observer);
if (!isExist) {
this.observers.push(observer);
}
}
detach(observer: Observer): void {
const observerIndex = this.observers.indexOf(observer);
if (observerIndex !== -1) {
this.observers.splice(observerIndex, 1);
}
}
notify(): void {
for (const observer of this.observers) {
observer.update(this.state);
}
}
setState(state: any): void {
this.state = state;
this.notify();
}
}
// 具体观察者
class ConcreteObserver implements Observer {
constructor(private name: string) {}
update(data: any): void {
console.log(`${this.name} received update with data: ${JSON.stringify(data)}`);
}
}
// 使用示例
const subject = new Subject();
const observer1 = new ConcreteObserver('Observer 1');
const observer2 = new ConcreteObserver('Observer 2');
subject.attach(observer1);
subject.attach(observer2);
subject.setState({ message: 'Hello!' });
6. 最佳实践和注意事项
模式选择:
- 根据实际需求选择合适的模式
- 避免过度设计
- 考虑维护成本
- 注意性能影响
实现考虑:
- 保持模式的简单性
- 提供清晰的文档
- 考虑错误处理
- 注意线程安全
测试策略:
- 单元测试覆盖
- 集成测试验证
- 性能测试
- 边界情况处理
性能优化:
- 延迟初始化
- 缓存机制
- 内存管理
- 避免过度抽象
// 综合示例:结合多个模式的实现
class ApplicationModule {
private static instance: ApplicationModule;
private services: Map<string, any> = new Map();
private observers: Set<Observer> = new Set();
private constructor() {
// 私有构造函数
}
static getInstance(): ApplicationModule {
if (!ApplicationModule.instance) {
ApplicationModule.instance = new ApplicationModule();
}
return ApplicationModule.instance;
}
// 工厂方法
createService<T>(type: string, factory: () => T): T {
if (!this.services.has(type)) {
const service = factory();
this.services.set(type, service);
return service;
}
return this.services.get(type);
}
// 观察者模式
subscribe(observer: Observer): void {
this.observers.add(observer);
}
unsubscribe(observer: Observer): void {
this.observers.delete(observer);
}
// 代理模式
getProxy<T>(target: T): T {
return new Proxy(target, {
get: (obj: any, prop: string) => {
console.log(`Accessing property: ${prop}`);
return obj[prop];
},
set: (obj: any, prop: string, value: any) => {
console.log(`Setting property: ${prop} = ${value}`);
obj[prop] = value;
return true;
},
});
}
}
这些高级模式为我们提供了强大的工具来构建复杂的应用程序。选择合适的模式时,应该考虑实际需求、维护成本和性能影响。同时,也要避免过度设计,保持代码的简单性和可维护性。
类型系统
泛型类
泛型类使得类可以处理多种数据类型,同时保持类型安全。
class Container<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
// 使用示例
const numberContainer = new Container<number>(123);
const stringContainer = new Container<string>('hello');
泛型约束
interface Lengthwise {
length: number;
}
class LengthChecker<T extends Lengthwise> {
checkLength(value: T): boolean {
return value.length > 0;
}
}
// 使用示例
const checker = new LengthChecker<string>();
console.log(checker.checkLength('test')); // true
类型守卫
类型守卫允许在运行时安全地检查对象的类型。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
}
class Cat extends Animal {
lives: number;
constructor(name: string, lives: number = 9) {
super(name);
this.lives = lives;
}
}
class AnimalHandler {
// instanceof 类型守卫
static isDog(animal: Animal): animal is Dog {
return animal instanceof Dog;
}
// 自定义类型守卫
static isCat(animal: Animal): animal is Cat {
return 'lives' in animal;
}
static handleAnimal(animal: Animal) {
if (AnimalHandler.isDog(animal)) {
console.log(`${animal.name} is a ${animal.breed} dog`);
} else if (AnimalHandler.isCat(animal)) {
console.log(`${animal.name} has ${animal.lives} lives`);
}
}
}
索引签名
索引签名允许类动态地添加和访问属性。
class DynamicMap {
[key: string]: any;
constructor(initialData: { [key: string]: any } = {}) {
Object.assign(this, initialData);
}
set(key: string, value: any): void {
this[key] = value;
}
get(key: string): any {
return this[key];
}
}
// 类型安全的索引签名
class TypedMap<T> {
[key: string]: T;
constructor(initialData: { [key: string]: T } = {}) {
Object.assign(this, initialData);
}
set(key: string, value: T): void {
this[key] = value;
}
get(key: string): T | undefined {
return this[key];
}
}
面向对象特性
继承
类继承允许创建基于现有类的新类。
class Vehicle {
constructor(
protected brand: string,
protected model: string
) {}
getInfo(): string {
return `${this.brand} ${this.model}`;
}
}
class Car extends Vehicle {
constructor(
brand: string,
model: string,
private doors: number
) {
super(brand, model);
}
getInfo(): string {
return `${super.getInfo()} with ${this.doors} doors`;
}
}
抽象类
抽象类提供了一个可以被继承但不能被实例化的基类。
abstract class Shape {
abstract getArea(): number;
abstract getPerimeter(): number;
getDescription(): string {
return `Area: ${this.getArea()}, Perimeter: ${this.getPerimeter()}`;
}
}
class Rectangle extends Shape {
constructor(
private width: number,
private height: number
) {
super();
}
getArea(): number {
return this.width * this.height;
}
getPerimeter(): number {
return 2 * (this.width + this.height);
}
}
接口实现
接口定义了类必须实现的契约。
interface Movable {
move(x: number, y: number): void;
getPosition(): { x: number; y: number };
}
interface Resizable {
resize(width: number, height: number): void;
getSize(): { width: number; height: number };
}
class Sprite implements Movable, Resizable {
constructor(
private x: number = 0,
private y: number = 0,
private width: number = 0,
private height: number = 0
) {}
move(x: number, y: number): void {
this.x = x;
this.y = y;
}
getPosition() {
return { x: this.x, y: this.y };
}
resize(width: number, height: number): void {
this.width = width;
this.height = height;
}
getSize() {
return { width: this.width, height: this.height };
}
}
静态成员
静态成员属于类本身而不是实例。
class Database {
private static instance: Database;
private static connections: number = 0;
private constructor() {}
static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}
static getConnectionCount(): number {
return Database.connections;
}
connect(): void {
Database.connections++;
}
disconnect(): void {
Database.connections--;
}
}
Getter 和 Setter
Getter 和 Setter 提供了属性访问的控制。
class Circle {
private _radius: number = 0;
get radius(): number {
return this._radius;
}
set radius(value: number) {
if (value >= 0) {
this._radius = value;
} else {
throw new Error('Radius cannot be negative');
}
}
get area(): number {
return Math.PI * this._radius ** 2;
}
get circumference(): number {
return 2 * Math.PI * this._radius;
}
}
高级特性
装饰器
装饰器用于修改类和类成员的行为。
// 类装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
// 方法装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with:`, args);
const result = originalMethod.apply(this, args);
console.log(`Result:`, result);
return result;
};
}
@sealed
class Example {
@log
multiply(a: number, b: number): number {
return a * b;
}
}
装饰器工厂
装饰器工厂允许自定义装饰器的行为。
// 类装饰器工厂
function withVersion(version: string) {
return function (constructor: Function) {
constructor.prototype.version = version;
};
}
// 方法装饰器工厂
function validate(validator: (value: any) => boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
if (args.every(validator)) {
return originalMethod.apply(this, args);
}
throw new Error('Validation failed');
};
};
}
@withVersion('1.0.0')
class Calculator {
@validate((n) => typeof n === 'number' && !isNaN(n))
add(a: number, b: number): number {
return a + b;
}
}
高级模式
TypeScript 类支持多种高级设计模式,这些模式可以帮助我们构建更加健壮和可维护的代码。
1. 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供对该实例的全局访问点。
使用场景:
- 全局状态管理
- 配置管理
- 数据库连接池
- 日志记录器
class Singleton {
private static instance: Singleton;
private constructor(private config: Record<string, any> = {}) {}
static getInstance(config?: Record<string, any>): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton(config);
}
return Singleton.instance;
}
// 线程安全的双重检查锁定模式
static getInstanceThreadSafe(config?: Record<string, any>): Singleton {
if (!Singleton.instance) {
// 在实际场景中,这里应该有适当的锁定机制
if (!Singleton.instance) {
Singleton.instance = new Singleton(config);
}
}
return Singleton.instance;
}
getConfig(): Record<string, any> {
return { ...this.config };
}
}
// 使用示例
const instance1 = Singleton.getInstance({ env: 'dev' });
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. 工厂模式(Factory Pattern)
工厂模式提供了创建对象的接口,让子类决定实例化哪个类。
使用场景:
- 对象创建的封装
- 依赖注入
- 平台特定实现
- 插件系统
// 产品接口
interface Animal {
makeSound(): void;
getType(): string;
}
// 具体产品
class Dog implements Animal {
makeSound(): void {
console.log('Woof!');
}
getType(): string {
return 'Dog';
}
}
class Cat implements Animal {
makeSound(): void {
console.log('Meow!');
}
getType(): string {
return 'Cat';
}
}
// 抽象工厂
abstract class AnimalFactory {
abstract createAnimal(): Animal;
// 工厂方法
static createAnimalFactory(type: string): AnimalFactory {
switch (type.toLowerCase()) {
case 'dog':
return new DogFactory();
case 'cat':
return new CatFactory();
default:
throw new Error(`Unknown animal type: ${type}`);
}
}
}
// 具体工厂
class DogFactory extends AnimalFactory {
createAnimal(): Animal {
return new Dog();
}
}
class CatFactory extends AnimalFactory {
createAnimal(): Animal {
return new Cat();
}
}
// 使用示例
const dogFactory = AnimalFactory.createAnimalFactory('dog');
const dog = dogFactory.createAnimal();
dog.makeSound(); // 输出: Woof!
3. Mixin 模式(Mixin Pattern)
Mixin 模式允许将行为注入到类中,实现代码重用和功能组合。
使用场景:
- 跨类共享行为
- 实现多重继承
- 装饰器模式的替代方案
- 功能模块化
// 定义 Mixin 类型
type Constructor<T = {}> = new (...args: any[]) => T;
// Mixin 函数
function Timestamped<TBase extends Constructor>(Base: TBase) {
return class extends Base {
timestamp = new Date();
getTimestamp(): Date {
return this.timestamp;
}
};
}
function Activatable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
isActive = false;
activate(): void {
this.isActive = true;
}
deactivate(): void {
this.isActive = false;
}
};
}
// 基础类
class User {
constructor(public name: string) {}
}
// 应用 Mixins
const TimestampedUser = Timestamped(User);
const TimestampedActivatableUser = Activatable(TimestampedUser);
// 使用示例
const user = new TimestampedActivatableUser('John');
console.log(user.getTimestamp());
user.activate();
console.log(user.isActive); // true
4. 代理模式(Proxy Pattern)
代理模式为其他对象提供一个代理以控制对这个对象的访问。
使用场景:
- 延迟加载
- 访问控制
- 日志记录
- 缓存实现
// 目标接口
interface IService {
getData(): Promise<string>;
}
// 实际服务
class RealService implements IService {
async getData(): Promise<string> {
// 模拟耗时操作
await new Promise((resolve) => setTimeout(resolve, 1000));
return 'Real service data';
}
}
// 代理类
class ServiceProxy implements IService {
private realService: RealService | null = null;
private cache: string | null = null;
async getData(): Promise<string> {
// 缓存检查
if (this.cache) {
console.log('Returning cached data');
return this.cache;
}
// 延迟初始化
if (!this.realService) {
console.log('Creating real service');
this.realService = new RealService();
}
// 获取数据并缓存
console.log('Fetching fresh data');
this.cache = await this.realService.getData();
return this.cache;
}
clearCache(): void {
this.cache = null;
}
}
// 使用示例
async function demo() {
const proxy = new ServiceProxy();
console.log(await proxy.getData()); // 首次调用,创建服务并获取数据
console.log(await proxy.getData()); // 使用缓存数据
proxy.clearCache();
console.log(await proxy.getData()); // 重新获取数据
}
5. 观察者模式(Observer Pattern)
观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知。
使用场景:
- 事件处理系统
- 状态同步
- UI 更新
- 消息推送
interface Observer {
update(data: any): void;
}
class Subject {
private observers: Observer[] = [];
private state: any;
attach(observer: Observer): void {
const isExist = this.observers.includes(observer);
if (!isExist) {
this.observers.push(observer);
}
}
detach(observer: Observer): void {
const observerIndex = this.observers.indexOf(observer);
if (observerIndex !== -1) {
this.observers.splice(observerIndex, 1);
}
}
notify(): void {
for (const observer of this.observers) {
observer.update(this.state);
}
}
setState(state: any): void {
this.state = state;
this.notify();
}
}
// 具体观察者
class ConcreteObserver implements Observer {
constructor(private name: string) {}
update(data: any): void {
console.log(`${this.name} received update with data: ${JSON.stringify(data)}`);
}
}
// 使用示例
const subject = new Subject();
const observer1 = new ConcreteObserver('Observer 1');
const observer2 = new ConcreteObserver('Observer 2');
subject.attach(observer1);
subject.attach(observer2);
subject.setState({ message: 'Hello!' });
6. 最佳实践和注意事项
模式选择:
- 根据实际需求选择合适的模式
- 避免过度设计
- 考虑维护成本
- 注意性能影响
实现考虑:
- 保持模式的简单性
- 提供清晰的文档
- 考虑错误处理
- 注意线程安全
测试策略:
- 单元测试覆盖
- 集成测试验证
- 性能测试
- 边界情况处理
性能优化:
- 延迟初始化
- 缓存机制
- 内存管理
- 避免过度抽象
// 综合示例:结合多个模式的实现
class ApplicationModule {
private static instance: ApplicationModule;
private services: Map<string, any> = new Map();
private observers: Set<Observer> = new Set();
private constructor() {
// 私有构造函数
}
static getInstance(): ApplicationModule {
if (!ApplicationModule.instance) {
ApplicationModule.instance = new ApplicationModule();
}
return ApplicationModule.instance;
}
// 工厂方法
createService<T>(type: string, factory: () => T): T {
if (!this.services.has(type)) {
const service = factory();
this.services.set(type, service);
return service;
}
return this.services.get(type);
}
// 观察者模式
subscribe(observer: Observer): void {
this.observers.add(observer);
}
unsubscribe(observer: Observer): void {
this.observers.delete(observer);
}
// 代理模式
getProxy<T>(target: T): T {
return new Proxy(target, {
get: (obj: any, prop: string) => {
console.log(`Accessing property: ${prop}`);
return obj[prop];
},
set: (obj: any, prop: string, value: any) => {
console.log(`Setting property: ${prop} = ${value}`);
obj[prop] = value;
return true;
},
});
}
}
这些高级模式为我们提供了强大的工具来构建复杂的应用程序。选择合适的模式时,应该考虑实际需求、维护成本和性能影响。同时,也要避免过度设计,保持代码的简单性和可维护性。
类的模块导入导出
1. 导出最佳实践
// models/user.ts
export interface UserData {
id: string;
name: string;
email: string;
}
export class User {
constructor(private data: UserData) {}
static fromJSON(json: string): User {
return new User(JSON.parse(json));
}
toJSON(): string {
return JSON.stringify(this.data);
}
}
// 导出类型
export type UserRole = 'admin' | 'user';
// 导出默认值
export default User;
2. 导入最佳实践
// services/user-service.ts
import User, { UserData, UserRole } from '../models/user';
export class UserService {
private users: Map<string, User> = new Map();
addUser(data: UserData): void {
const user = new User(data);
this.users.set(data.id, user);
}
getUser(id: string): User | undefined {
return this.users.get(id);
}
}
类的单元测试
1. Jest 测试示例
// user.test.ts
import { User, UserData } from './user';
describe('User', () => {
let userData: UserData;
let user: User;
beforeEach(() => {
userData = {
id: '1',
name: 'John Doe',
email: 'john@example.com',
};
user = new User(userData);
});
test('creates user from JSON', () => {
const json = JSON.stringify(userData);
const userFromJSON = User.fromJSON(json);
expect(userFromJSON).toBeInstanceOf(User);
});
test('converts to JSON', () => {
const json = user.toJSON();
const parsed = JSON.parse(json);
expect(parsed).toEqual(userData);
});
});
2. 测试最佳实践
// calculator.test.ts
import { Calculator } from './calculator';
describe('Calculator', () => {
let calculator: Calculator;
// 在每个测试前创建新实例
beforeEach(() => {
calculator = new Calculator();
});
// 分组相关测试
describe('add', () => {
test('adds positive numbers', () => {
expect(calculator.add(2, 3)).toBe(5);
});
test('adds negative numbers', () => {
expect(calculator.add(-2, -3)).toBe(-5);
});
test('adds zero', () => {
expect(calculator.add(2, 0)).toBe(2);
});
});
// 测试异常
describe('divide', () => {
test('throws error when dividing by zero', () => {
expect(() => calculator.divide(1, 0)).toThrow('Division by zero');
});
});
});
类的性能优化
1. 内存管理
class ResourceManager {
private resources: Map<string, WeakRef<Resource>> = new Map();
private cleanupInterval: number;
constructor() {
// 定期清理失效的引用
this.cleanupInterval = setInterval(() => this.cleanup(), 5000);
}
addResource(id: string, resource: Resource): void {
this.resources.set(id, new WeakRef(resource));
}
getResource(id: string): Resource | undefined {
const ref = this.resources.get(id);
return ref?.deref();
}
private cleanup(): void {
for (const [id, ref] of this.resources.entries()) {
if (!ref.deref()) {
this.resources.delete(id);
}
}
}
dispose(): void {
clearInterval(this.cleanupInterval);
this.resources.clear();
}
}
2. 性能优化技巧
class OptimizedList<T> {
private items: T[] = [];
private cache: Map<string, T> = new Map();
// 使用缓存优化查找
find(predicate: (item: T) => boolean): T | undefined {
const cacheKey = predicate.toString();
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const result = this.items.find(predicate);
if (result) {
this.cache.set(cacheKey, result);
}
return result;
}
// 批量操作优化
addMany(items: T[]): void {
// 预分配数组空间
this.items = [...this.items, ...items];
// 一次性触发更新
this.notifyUpdate();
}
private notifyUpdate(): void {
// 实现更新通知逻辑
}
}
类的文档注释
1. JSDoc/TSDoc 规范
/**
* 表示一个用户实体。
* 处理用户数据的存储和验证。
*
* @class User
* @implements {IUser}
* @template T - 用户数据的类型
*
* @example
* ```js
* const user = new User<UserData>({
* id: '1',
* name: 'John Doe',
* email: 'john@example.com'
* });
* ```
*/
class User<T extends UserData> implements IUser<T> {
/**
* 创建一个新的用户实例
*
* @constructor
* @param {T} data - 用户数据
* @throws {ValidationError} 如果数据验证失败
*/
constructor(private data: T) {
this.validate();
}
/**
* 验证用户数据
*
* @private
* @returns {void}
* @throws {ValidationError} 如果验证失败
*/
private validate(): void {
if (!this.data.email.includes('@')) {
throw new ValidationError('Invalid email format');
}
}
/**
* 更新用户数据
*
* @param {Partial<T>} updates - 要更新的字段
* @returns {void}
* @emits {UserUpdated} 当用户数据更新时
*/
update(updates: Partial<T>): void {
Object.assign(this.data, updates);
this.validate();
}
}
2. 文档生成
/**
* @packageDocumentation
* 这是用户管理模块的主要文档。
* 包含了所有用户相关的类和接口。
*/
/**
* 用户管理器类
* @remarks
* 这个类负责处理所有用户相关的操作。
*
* @public
*/
export class UserManager {
/**
* 用户列表
* @internal
*/
private users: Map<string, User> = new Map();
/**
* 添加新用户
* @param user - 要添加的用户对象
* @returns 添加是否成功
* @beta
*/
addUser(user: User): boolean {
if (this.users.has(user.id)) {
return false;
}
this.users.set(user.id, user);
return true;
}
/**
* 获取用户信息
* @param id - 用户ID
* @returns 用户对象,如果不存在则返回undefined
* @throws {UserNotFoundError} 当用户不存在时
*/
getUser(id: string): User {
const user = this.users.get(id);
if (!user) {
throw new UserNotFoundError(id);
}
return user;
}
}