类、继承与修饰器

本节目标

TS 的 class 同时是「类型」和「运行时代码」。

// 运行环境:Node.js 16+ + typescript(需开启 experimentalDecorators 或 TS 5.0+);
// 运行:npx tsc ts-l13.ts && node ts-l13.js

// 用 interface 约束「类必须实现哪些方法」
interface Logger {
  log(msg: string): void
}

class FileLogger implements Logger {
  private filePath: string // private:仅类内部可见
  constructor(path: string) {
    this.filePath = path
  }
  log(msg: string): void {
    console.log(`[${this.filePath}] ${msg}`)
  }
}

// 继承:复用 + 扩展
class TimestampLogger extends FileLogger {
  log(msg: string): void {
    super.log(`[${new Date().toISOString()}] ${msg}`)
  }
}

const logger = new TimestampLogger('app.log')
logger.log('启动') // [app.log] [2026-...] 启动

修饰器(TS 5 稳定特性)是「贴在类/方法上的注解」,编译期/运行期增强行为:

// 一个「方法耗时统计」修饰器
function measure(target: any, key: string, desc: PropertyDescriptor) {
  const fn = desc.value
  desc.value = function (...args: any[]) {
    const t = Date.now()
    const r = fn.apply(this, args)
    console.log(`${key} 耗时 ${Date.now() - t}ms`)
    return r
  }
}
class Calc {
  @measure
  heavy(): number { return 1 + 1 }
}
new Calc().heavy() // 打印耗时

名词解释

类(class):TS 里 class 同时身兼两职:既是「运行时创建对象的蓝图」(new 出实例),又是「类型」(能当注解用)。implements 表示「这个类承诺实现某个接口的所有成员」;extends 表示「继承另一个类,复用它的能力」。

修饰器(Decorator):一种「贴在类/属性/方法上的标签」,用来在不改动原代码的前提下给它加功能(日志、缓存、校验等)。它本质是「编译期/运行期的包裹函数」。NestJS、Angular 大量用它,是 TS 工程化的标志性特性。

课后练习

练习 1:写 Animal 基类(有 name 和 eat()),Dog 继承它并新增 bark()。

答案:

class Animal {
  constructor(public name: string) {}
  eat(): void { console.log(`${this.name} 吃`) }
}
class Dog extends Animal {
  bark(): void { console.log('汪') }
}

练习 2:private 和「不写修饰符(默认 public)」有什么区别?

答案:默认 public,类外也能访问;private 仅在类内部可访问,类外访问会编译报错,是 TS 编译期的访问限制(运行时仍是普通属性)。protected 则允许子类访问、禁止外部。

总结

我的观点:TS 的 class 让「面向对象」在前端有了类型保障,但请记住前端其实没那么需要继承。很多初学者一上来就 extends 一大串,结果耦合得改不动。我的经验法则是:能用组合(把小对象拼起来)就别用继承;只有「确实是『是一种(is-a)』关系且要复用行为」才继承。修饰器则是「横切关注点」(日志、权限、缓存)的利器,能显著减少重复包裹代码,但别为了炫技而加——每个修饰器都要解决一个真实重复问题。最后提醒:private 只是编译期约定,不是运行时加密,别拿它当安全边界。