📦 类的基础
TypeScript 的类语法与 Java/C++ 非常接近,但底层编译为 JavaScript 的原型链机制。
class Animal {
name: string;
sound: string;
constructor(name: string, sound: string) {
this.name = name;
this.sound = sound;
}
speak(): string {
return `${this.name} says ${this.sound}!`;
}
}
const cat = new Animal("小猫", "喵");
console.log(cat.speak()); // "小猫 says 喵!"
💡 与 Java/C++ 的关键区别:
TypeScript 的类属性必须在类体中声明或在构造函数中通过参数属性简写声明。不像 Java 那样可以直接在构造函数中使用未声明的字段。
🔒 访问修饰符
TypeScript 提供三个访问修饰符,与 Java/C++ 的概念一致。
class BankAccount {
public owner: string; // 公开(默认)
protected balance: number; // 子类可访问
private pin: string; // 仅类内部可访问
readonly accountId: string; // 只读,初始化后不可修改
constructor(owner: string, balance: number, pin: string) {
this.owner = owner;
this.balance = balance;
this.pin = pin;
this.accountId = crypto.randomUUID();
}
public getBalance(): number { return this.balance; }
private validatePin(input: string): boolean { return input === this.pin; }
public withdraw(amount: number, pin: string): boolean {
if (!this.validatePin(pin) || amount > this.balance) return false;
this.balance -= amount;
return true;
}
}
ES 原生私有字段(运行时真正隔离):
class SecureVault {
#secret: string; // 真正的私有字段,运行时也无法从外部访问
constructor(secret: string) {
this.#secret = secret;
}
reveal(): string {
return this.#secret;
}
}
const vault = new SecureVault("密码");
// vault.#secret; // ❌ 语法错误:运行时和编译时都不允许
🔄 与 Java 的对比:
TS 的 private 是编译时检查,运行时仍可通过 (obj as any).pin 访问。如需运行时隔离,使用 #field 语法(ES2022 私有字段)。
🔄 与 Python 的对比:
Python 用 _(约定私有)和 __(名称改写)来表示访问级别,TS 有显式的 public/private/protected 关键字,在编译期严格检查。
✨ 参数属性简写
这是 TypeScript 特有的语法糖——在构造函数参数前加访问修饰符,自动声明并赋值同名属性。
// ❌ 传统写法需要:声明属性 → 构造函数参数 → 手动赋值(三步)
// ✅ 参数属性简写:一步到位
class User {
constructor(
public name: string,
private age: number,
readonly email: string,
) {}
getAge(): number {
return this.age;
}
}
💡 实战建议:
参数属性简写在简单数据类中极为常用。但如果构造函数有复杂逻辑(如参数校验),混用简写和手动赋值可能降低可读性。
🧬 继承
使用 extends 关键字实现类继承,与 Java 的单继承模型一致。
class Animal {
constructor(public name: string, protected sound: string) {}
speak(): string { return `${this.name}: ${this.sound}`; }
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name, "汪汪"); // 必须调用 super()
}
speak(): string {
return `🐕 ${super.speak()}!(品种:${this.breed})`;
}
fetch(item: string): string {
return `${this.name} 捡回了 ${item}`;
}
}
const dog = new Dog("旺财", "金毛");
console.log(dog.speak()); // "🐕 旺财: 汪汪!(品种:金毛)"
console.log(dog.fetch("飞盘")); // "旺财 捡回了 飞盘"
🎨 抽象类
抽象类不能直接实例化,用于定义子类必须实现的模板方法。
abstract class Shape {
abstract area(): number;
abstract perimeter(): number;
describe(): string {
return `面积: ${this.area().toFixed(2)}, 周长: ${this.perimeter().toFixed(2)}`;
}
}
class Circle extends Shape {
constructor(private radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
perimeter(): number { return 2 * Math.PI * this.radius; }
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) { super(); }
area(): number { return this.width * this.height; }
perimeter(): number { return 2 * (this.width + this.height); }
}
// const s = new Shape(); // ❌ 不能实例化抽象类
const circle = new Circle(5);
console.log(circle.describe()); // "面积: 78.54, 周长: 31.42"
🔌 接口实现
用 implements 显式声明类遵循某个接口契约。一个类可以实现多个接口。
interface Serializable {
serialize(): string;
}
interface Printable {
print(): void;
}
class Document implements Serializable, Printable {
constructor(public title: string, public content: string) {}
serialize(): string {
return JSON.stringify({ title: this.title, content: this.content });
}
print(): void {
console.log(`=== ${this.title} ===\n${this.content}`);
}
}
// 接口约束函数参数
function save(item: Serializable): void {
const data = item.serialize();
console.log("保存数据:", data);
}
const doc = new Document("笔记", "TypeScript 很棒");
save(doc);
💡 extends vs implements:
extends:继承一个类,获得其实现代码implements:声明遵循接口契约,必须自己实现所有方法- 可以同时使用:
class A extends B implements C, D
⚡ 静态成员
静态属性和方法属于类本身,不属于实例。常用于工厂模式和工具方法。
class IdGenerator {
private static nextId: number = 1;
static generate(): number {
return IdGenerator.nextId++;
}
static reset(): void {
IdGenerator.nextId = 1;
}
}
console.log(IdGenerator.generate()); // 1
console.log(IdGenerator.generate()); // 2
// 单例模式
class Config {
private static instance: Config | null = null;
private constructor(public readonly env: string) {}
static getInstance(): Config {
if (!Config.instance) {
Config.instance = new Config(process.env.NODE_ENV ?? "development");
}
return Config.instance;
}
}
🎭 装饰器简介
装饰器是一种特殊语法,用于在不修改原始代码的情况下增强类和方法的行为。在 NestJS、Angular 等框架中广泛使用。
// 方法装饰器:自动记录方法调用日志
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`调用 ${propertyKey}(${args.join(", ")})`);
const result = original.apply(this, args);
console.log(`${propertyKey} 返回: ${result}`);
return result;
};
}
class UserService {
@log
findById(id: number): string {
return `User_${id}`;
}
}
const service = new UserService();
service.findById(42);
// 输出:
// 调用 findById(42)
// findById 返回: User_42
⚠️ 注意事项:
TypeScript 5.0+ 支持 TC39 Stage 3 装饰器标准。旧版实验性装饰器需要在 tsconfig.json 中启用 "experimentalDecorators": true。NestJS 和 Angular 目前仍使用旧版语法。
📝 本章要点
类基础
属性声明、构造函数、方法——语法与 Java/C++ 相似,编译为 JS 原型链
访问修饰符
public/private/protected/readonly;#field 提供运行时隔离
参数属性简写
构造函数参数加修饰符,自动声明+赋值——TypeScript 独有的语法糖
继承与抽象类
extends 单继承;abstract 定义模板方法,子类必须实现
接口实现
implements 声明契约,支持多接口实现
静态成员与装饰器
静态成员用于工厂/单例;装饰器增强类行为,框架中广泛使用