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 控制编译与类型检查行为 项目初始化、严格度配置、路径别名
相关推荐
pppiii23 分钟前
前端并发请求控制:5 种实现方案完整梳理
前端
郑州光合科技余经理38 分钟前
本地生活平台搭建:统一订单表与多后台切换怎么拆
java·开发语言·前端·系统架构·uni-app·php·ai编程
iFlyCai1 小时前
深入理解Flutter:StatefulWidget生命周期全解析(四)
前端·javascript·flutter
xm_xm_xm_12 小时前
Vue 3 项目开发常用操作详细汇总
前端·vue.js
计算机魔术师2 小时前
我国日均词元调用量突破 500 万亿,中国大模型稳居全球第一梯队
前端
码视野2 小时前
基于 Spring Boot + Vue3 的【高校化学实验室安全准入考试与危化品配伍排查系统】设计与实现(含PRD/三端高保真源码/大屏)
前端·人工智能·spring boot·后端·安全·vue3
玄魂2 小时前
VisActor 全新图可视化开源项目:VGraph
前端·数据可视化
宇智波亚索3 小时前
TypeScript 实际应用
前端·javascript·typescript
明飞19873 小时前
C表达式_表达式类型
前端