TypeScript 7 个 核心特性

通过完整可运行的代码示例,逐一深入讲解这 TypeScript 7 个 核心特性。


1. 接口(Interface)

作用

定义对象的结构契约,描述"一个对象应该长什么样",但不提供具体实现。用于类型检查、代码约定、团队协作。

详细示例

typescript 复制代码
// ========== 基础接口 ==========
interface User {
  id: number;
  name: string;
  email: string;
  isActive?: boolean;        // 可选属性
  readonly createdAt: Date;   // 只读属性,创建后不可修改
}

// 使用接口约束对象
const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com",
  createdAt: new Date()
};

// user.createdAt = new Date(); // ❌ 错误:readonly 属性不可修改

// ========== 接口描述函数形状 ==========
interface SearchFunc {
  (source: string, subString: string): boolean;
}

const mySearch: SearchFunc = (src, sub) => {
  return src.includes(sub);
};

// ========== 接口继承(扩展) ==========
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
  bark(): void;
}

const myDog: Dog = {
  name: "旺财",
  breed: "金毛",
  bark() {
    console.log("汪汪!");
  }
};

// ========== 接口实现类(与 class 结合) ==========
interface Printable {
  print(): void;
  getContent(): string;
}

class Document implements Printable {
  constructor(private content: string) {}

  print() {
    console.log(`打印内容:${this.content}`);
  }

  getContent() {
    return this.content;
  }
}

const doc = new Document("合同文件");
doc.print(); // 打印内容:合同文件

// ========== 索引签名(动态属性) ==========
interface StringDictionary {
  [key: string]: string;
}

const translations: StringDictionary = {
  hello: "你好",
  world: "世界"
};

实际应用场景

  • API 响应类型定义:前后端约定数据结构
  • 组件 Props 类型:React/Vue 组件入参约束
  • 插件系统:定义插件必须实现的接口

2. 类与访问修饰符

作用

控制类成员的可见性,实现封装,防止外部随意修改内部状态。

详细示例

typescript 复制代码
// ========== 三种访问修饰符 ==========
class BankAccount {
  // public: 公开(默认),任何地方可访问
  public accountNumber: string;

  // private: 仅类内部可访问,实例和子类都不可访问
  private balance: number;

  // protected: 类内部和子类可访问,实例不可访问
  protected ownerName: string;

  constructor(accountNumber: string, ownerName: string, initialBalance: number) {
    this.accountNumber = accountNumber;
    this.ownerName = ownerName;
    this.balance = initialBalance;
  }

  // public 方法
  public deposit(amount: number): void {
    if (amount <= 0) {
      throw new Error("存款金额必须大于0");
    }
    this.balance += amount;
    this.logTransaction("存款", amount);
  }

  public withdraw(amount: number): void {
    if (amount > this.balance) {
      throw new Error("余额不足");
    }
    this.balance -= amount;
    this.logTransaction("取款", amount);
  }

  public getBalance(): number {
    return this.balance;
  }

  // private 方法:内部辅助逻辑
  private logTransaction(type: string, amount: number): void {
    console.log(`[${new Date().toISOString()}] ${type}: ¥${amount}`);
  }
}

// ========== 使用 ==========
const account = new BankAccount("622202123456", "张三", 1000);

account.deposit(500);
console.log(account.getBalance());      // 1500
console.log(account.accountNumber);     // ✅ 可以访问 public

// account.balance = 999999;            // ❌ 错误:属性是 private
// account.ownerName;                   // ❌ 错误:属性是 protected

// ========== protected 在继承中的使用 ==========
class SavingsAccount extends BankAccount {
  private interestRate: number;

  constructor(accountNumber: string, ownerName: string, balance: number, rate: number) {
    super(accountNumber, ownerName, balance);
    this.interestRate = rate;
  }

  public applyInterest(): void {
    // 子类可以访问 protected 的 ownerName
    console.log(`为 ${this.ownerName} 计算利息`);
    const interest = this.getBalance() * this.interestRate;
    this.deposit(interest);
  }
}

const savings = new SavingsAccount("622202999999", "李四", 10000, 0.03);
savings.applyInterest();
// 输出:为 李四 计算利息

参数属性简写(语法糖)

typescript 复制代码
class Person {
  // 直接在构造函数参数中声明属性,自动赋值
  constructor(
    public name: string,
    private age: number,
    protected id: string
  ) {}
}

const p = new Person("王五", 25, "ID001");
console.log(p.name); // 王五

3. 抽象类与实现

作用

  • 抽象类 :不能被实例化,只能被继承,用于定义子类的通用模板
  • 抽象方法:只有声明没有实现,强制子类必须实现

详细示例

typescript 复制代码
// ========== 抽象类定义 ==========
abstract class Shape {
  // 抽象属性(子类必须实现)
  abstract name: string;

  // 具体属性(子类继承即用)
  color: string = "black";

  // 抽象方法:只有签名,没有实现
  abstract calculateArea(): number;
  abstract calculatePerimeter(): number;

  // 具体方法:所有子类共享的实现
  describe(): string {
    return `这是一个${this.color}色的${this.name},` +
           `面积=${this.calculateArea()},` +
           `周长=${this.calculatePerimeter()}`;
  }
}

// ========== 具体实现类 ==========
class Rectangle extends Shape {
  name = "矩形";

  constructor(
    public width: number,
    public height: number,
    color: string = "蓝色"
  ) {
    super();
    this.color = color;
  }

  calculateArea(): number {
    return this.width * this.height;
  }

  calculatePerimeter(): number {
    return 2 * (this.width + this.height);
  }
}

class Circle extends Shape {
  name = "圆形";

  constructor(
    public radius: number,
    color: string = "红色"
  ) {
    super();
    this.color = color;
  }

  calculateArea(): number {
    return Math.PI * this.radius ** 2;
  }

  calculatePerimeter(): number {
    return 2 * Math.PI * this.radius;
  }
}

// ========== 使用 ==========
// const shape = new Shape(); // ❌ 错误:无法创建抽象类的实例

const rect = new Rectangle(10, 5, "绿色");
console.log(rect.describe());
// 输出:这是一个绿色的矩形,面积=50,周长=30

const circle = new Circle(7);
console.log(circle.describe());
// 输出:这是一个红色的圆形,面积=153.9380...,周长=43.9822...

// ========== 多态使用 ==========
const shapes: Shape[] = [rect, circle];
shapes.forEach(s => console.log(s.describe()));

与接口的区别

抽象类 接口
实现 可包含具体方法和属性 只能声明,不能实现
继承 单继承(一个类只能 extends 一个) 多实现(一个类可 implements 多个)
实例化 不能 不能
用途 代码复用 + 模板约束 纯契约定义

4. 模块与命名空间

作用

  • 模块(Module) :基于文件的组织方式,每个文件是一个模块,通过 import/export 管理依赖
  • 命名空间(Namespace):用于将相关代码组织到同一个命名空间下,避免全局污染

详细示例

模块系统(现代推荐方式)
typescript 复制代码
// ========== math-utils.ts ==========
// 命名导出
export function add(a: number, b: number): number {
  return a + b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

// 默认导出
export default class Calculator {
  private history: string[] = [];

  execute(operation: string, a: number, b: number): number {
    let result: number;
    switch(operation) {
      case 'add': result = add(a, b); break;
      case 'multiply': result = multiply(a, b); break;
      default: throw new Error("未知操作");
    }
    this.history.push(`${operation}(${a}, ${b}) = ${result}`);
    return result;
  }

  getHistory(): string[] {
    return [...this.history];
  }
}

// 类型导出
export interface MathConfig {
  precision: number;
  allowNegative: boolean;
}
typescript 复制代码
// ========== main.ts ==========
// 默认导入
import Calculator from './math-utils';

// 命名导入
import { add, multiply, MathConfig } from './math-utils';

// 全部导入为命名空间
import * as MathUtils from './math-utils';

// 使用
const calc = new Calculator();
console.log(calc.execute('add', 5, 3));      // 8
console.log(add(10, 20));                     // 30

const config: MathConfig = {
  precision: 2,
  allowNegative: false
};
命名空间(适合大型库内部组织)
typescript 复制代码
// ========== 命名空间定义 ==========
namespace Validation {
  export interface StringValidator {
    isValid(s: string): boolean;
  }

  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

  export class EmailValidator implements StringValidator {
    isValid(s: string): boolean {
      return emailRegex.test(s);
    }
  }

  export class PhoneValidator implements StringValidator {
    isValid(s: string): boolean {
      return /^1[3-9]\d{9}$/.test(s);
    }
  }

  // 未 export 的只能在命名空间内部使用
  function logValidation(result: boolean): void {
    console.log(`验证结果:${result ? '通过' : '失败'}`);
  }
}

// ========== 使用 ==========
const emailVal = new Validation.EmailValidator();
console.log(emailVal.isValid("test@example.com")); // true

const phoneVal = new Validation.PhoneValidator();
console.log(phoneVal.isValid("13800138000"));    // true

// 嵌套命名空间
namespace App {
  export namespace Utils {
    export function formatDate(d: Date): string {
      return d.toLocaleDateString('zh-CN');
    }
  }
}

console.log(App.Utils.formatDate(new Date()));

现代项目推荐 :优先使用模块(ES Module),命名空间主要用于遗留代码或需要打包成单个全局变量的库。


5. 装饰器(Decorators)

作用

装饰器是一种特殊类型的声明 ,可以附加到类、方法、属性或参数上,用于修改或增强它们的行为。广泛用于 NestJS、Angular、TypeORM 等框架。

详细示例

需要先开启装饰器支持(见第 7 节配置)。

typescript 复制代码
// ========== 类装饰器 ==========
function LogClass(target: Function) {
  console.log(`类 ${target.name} 被创建了`);
}

@LogClass
class UserService {
  constructor() {
    console.log("UserService 实例化");
  }
}
// 输出:类 UserService 被创建了

// ========== 方法装饰器 ==========
function MeasureTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} 执行耗时: ${(end - start).toFixed(2)}ms`);
    return result;
  };

  return descriptor;
}

class DataProcessor {
  @MeasureTime
  heavyComputation(n: number): number {
    let sum = 0;
    for (let i = 0; i < n; i++) {
      sum += Math.sqrt(i);
    }
    return sum;
  }
}

const processor = new DataProcessor();
processor.heavyComputation(1000000);
// 输出:heavyComputation 执行耗时: 12.34ms

// ========== 属性装饰器 ==========
function Required(target: any, propertyKey: string) {
  // 注册验证规则
  let validators = target.constructor.prototype._validators || [];
  validators.push({ field: propertyKey, type: 'required' });
  target.constructor.prototype._validators = validators;
}

function Validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    const validators = this._validators || [];
    for (const v of validators) {
      if (v.type === 'required' && !this[v.field]) {
        throw new Error(`验证失败:${v.field} 不能为空`);
      }
    }
    return original.apply(this, args);
  };
}

class User {
  @Required
  name: string = "";

  @Required
  email: string = "";

  @Validate
  save() {
    console.log(`保存用户:${this.name}, ${this.email}`);
  }
}

const user = new User();
// user.save(); // ❌ 抛出错误:验证失败:name 不能为空

user.name = "张三";
user.email = "zs@example.com";
user.save(); // ✅ 保存用户:张三, zs@example.com

// ========== 参数装饰器(NestJS 风格) ==========
function Body() {
  return function (target: any, propertyKey: string, parameterIndex: number) {
    // 标记参数需要从请求体中获取
    const metadata = Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];
    console.log(`方法 ${propertyKey} 的第 ${parameterIndex} 个参数标记为 Body`);
  };
}

class UserController {
  createUser(@Body() userData: any) {
    console.log("创建用户:", userData);
  }
}

装饰器工厂(带参数的装饰器)

typescript 复制代码
function Cacheable(ttlSeconds: number) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const cache = new Map();
    const original = descriptor.value;

    descriptor.value = function (...args: any[]) {
      const key = JSON.stringify(args);
      if (cache.has(key)) {
        console.log("命中缓存");
        return cache.get(key);
      }
      const result = original.apply(this, args);
      cache.set(key, result);
      setTimeout(() => cache.delete(key), ttlSeconds * 1000);
      return result;
    };
  };
}

class ApiService {
  @Cacheable(60) // 缓存 60 秒
  fetchUser(id: number) {
    console.log(`发起网络请求获取用户 ${id}`);
    return { id, name: `用户${id}` };
  }
}

const api = new ApiService();
api.fetchUser(1); // 发起网络请求
api.fetchUser(1); // 命中缓存

6. 泛型编程

作用

编写类型安全的通用代码,让函数/类/接口可以处理多种类型,同时保持类型推断和检查。

详细示例

typescript 复制代码
// ========== 泛型函数 ==========
// T 是类型参数,调用时传入或自动推断
function identity<T>(arg: T): T {
  return arg;
}

const num = identity<number>(42);     // num 类型是 number
const str = identity("hello");        // 自动推断为 string

// ========== 泛型约束 ==========
interface HasLength {
  length: number;
}

// T 必须具有 length 属性
function logLength<T extends HasLength>(arg: T): T {
  console.log(`长度:${arg.length}`);
  return arg;
}

logLength("hello");        // ✅ 长度:5
logLength([1, 2, 3]);    // ✅ 长度:3
// logLength(123);         // ❌ 错误:number 没有 length

// ========== 泛型接口 ==========
interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

// 复用同一接口结构,数据类型不同
const userResponse: ApiResponse<{ id: number; name: string }> = {
  code: 200,
  message: "成功",
  data: { id: 1, name: "张三" }
};

const listResponse: ApiResponse<string[]> = {
  code: 200,
  message: "成功",
  data: ["a", "b", "c"]
};

// ========== 泛型类 ==========
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }

  isEmpty(): boolean {
    return this.items.length === 0;
  }
}

// 数字栈
const numberStack = new Stack<number>();
numberStack.push(10);
numberStack.push(20);
// numberStack.push("hello"); // ❌ 错误

// 字符串栈
const stringStack = new Stack<string>();
stringStack.push("first");
stringStack.push("second");

// ========== 泛型工具类型 ==========
interface Person {
  name: string;
  age: number;
  email: string;
}

// Partial<T>:所有属性变为可选
const partialPerson: Partial<Person> = { name: "张三" };

// Pick<T, K>:从 T 中选取部分属性
type PersonName = Pick<Person, 'name' | 'age'>; // { name: string; age: number }

// Omit<T, K>:从 T 中排除部分属性
type PersonWithoutEmail = Omit<Person, 'email'>; // { name: string; age: number }

// Record<K, T>:创建键值对类型
const scoreMap: Record<string, number> = {
  "张三": 90,
  "李四": 85
};

// ========== 高级:条件类型与映射类型 ==========
type IsString<T> = T extends string ? true : false;

type A = IsString<"hello">;  // true
type B = IsString<123>;      // false

// 将对象所有属性变为只读
type ReadonlyPerson = Readonly<Person>;
// 等价于:{ readonly name: string; readonly age: number; readonly email: string; }

7. 配置与工具链

作用

tsconfig.json 是 TypeScript 项目的核心配置文件,控制编译行为、类型检查严格程度、输出目标等。

完整配置示例与详解

json 复制代码
{
  // ========== 编译选项 ==========
  "compilerOptions": {
    // --- 目标与模块 ---
    "target": "ES2020",           // 编译目标 JS 版本:ES3/ES5/ES6/ES2017/ES2020/ESNext
    "module": "ESNext",           // 模块系统:CommonJS/AMD/UMD/System/ESNext
    "lib": ["ES2020", "DOM"],     // 包含的类型定义库

    // --- 输出配置 ---
    "outDir": "./dist",           // 编译输出目录
    "rootDir": "./src",           // 源码根目录
    "declaration": true,          // 生成 .d.ts 类型声明文件(开发库时必备)
    "declarationDir": "./types", // 声明文件输出目录
    "sourceMap": true,            // 生成 .map 文件,用于调试
    "removeComments": true,       // 编译时移除注释

    // --- 严格类型检查(强烈推荐开启)---
    "strict": true,               // 启用所有严格类型检查选项
    "noImplicitAny": true,        // 禁止隐式 any(表达式/声明没有类型时)
    "strictNullChecks": true,     // null/undefined 不能赋值给其他类型
    "strictFunctionTypes": true,  // 函数参数双向协变检查
    "noImplicitReturns": true,    // 函数必须有显式返回值
    "noFallthroughCasesInSwitch": true, // switch 禁止 case 穿透

    // --- 代码质量 ---
    "noUnusedLocals": true,       // 报错未使用的局部变量
    "noUnusedParameters": true,   // 报错未使用的参数(可用 _ 前缀忽略)
    "noImplicitOverride": true,   // 重写父类方法必须加 override 关键字

    // --- 模块解析 ---
    "moduleResolution": "node",   // 模块解析策略:node/classic
    "baseUrl": ".",               // 基础路径,用于路径别名
    "paths": {                    // 路径别名映射
      "@/*": ["src/*"],
      "@utils/*": ["src/utils/*"]
    },
    "esModuleInterop": true,      // 兼容 CommonJS 模块的默认导入
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,    // 允许导入 JSON 文件

    // --- JSX(React 项目)---
    "jsx": "react-jsx",           // react-jsx/react/preserve
    "jsxImportSource": "react",

    // --- 装饰器 ---
    "experimentalDecorators": true,      // 启用装饰器
    "emitDecoratorMetadata": true,       // 为装饰器生成元数据(TypeORM 等需要)

    // --- 其他 ---
    "skipLibCheck": true,         // 跳过 node_modules 中声明文件的类型检查(加速编译)
    "forceConsistentCasingInFileNames": true  // 强制文件名大小写一致
  },

  // ========== 包含/排除文件 ==========
  "include": [
    "src/**/*",           // 编译 src 目录下所有文件
    "types/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "**/*.test.ts",       // 排除测试文件
    "**/*.spec.ts"
  ],

  // ========== 项目引用(大型项目分模块编译)==========
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/core" }
  ]
}

实际使用方式

bash 复制代码
# 1. 初始化项目
npm init -y
npm install typescript --save-dev
npx tsc --init          # 生成 tsconfig.json

# 2. 开发时实时编译(监视模式)
npx tsc --watch

# 3. 生产构建
npx tsc                 # 一次性编译

# 4. 配合构建工具(推荐)
# Vite(零配置支持 TS)
npm create vite@latest my-app -- --template react-ts

# Webpack
npm install ts-loader --save-dev

# esbuild / swc(超高速编译)
npm install esbuild --save-dev

路径别名实战

typescript 复制代码
// tsconfig.json 中配置
// "paths": { "@/*": ["src/*"] }

// 实际代码中使用
import { formatDate } from '@/utils/date';
import { User } from '@/types/user';
// 替代冗长的相对路径:../../../utils/date

严格模式渐进开启策略

json 复制代码
// 新项目:直接 strict: true
// 老项目迁移:逐步开启
{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true,        // 第一步:先解决隐式 any
    "strictNullChecks": false,     // 第二步:后续逐步开启
    "strictFunctionTypes": false
  }
}

总结速查表

特性 核心作用 典型使用场景
Interface 定义对象结构契约 API 类型、组件 Props、类实现规范
访问修饰符 控制可见性,实现封装 保护内部状态,防止非法修改
抽象类 定义通用模板,强制子类实现 框架基类、插件系统、多态处理
模块/命名空间 代码组织与隔离 项目模块化、避免全局污染
装饰器 元编程,增强类/方法/属性 AOP 日志、权限校验、缓存、依赖注入
泛型 类型安全的通用代码 工具函数、数据结构、API 封装
tsconfig 控制编译与类型检查行为 项目初始化、严格度配置、路径别名
相关推荐
AlienZHOU3 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc6 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师8 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen8 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒8 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow9 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林8189 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang800789 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明9 小时前
第 6 章 组件进阶
前端·vue.js
江华森9 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端