7Programming TypeScript

声明文件

类型声明

d.tsdeclare模块声明全局类型

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第7章:声明文件(Declaration Files)

一、导读

1.1 本章学习目标

第7章讲解 TypeScript 的声明文件(.d.ts)——如何为 JavaScript 库编写类型定义,以及如何发布和管理类型声明。

本章的核心学习目标包括:

  • 理解声明文件的作用和格式
  • 掌握 `declare` 关键字的各种用法
  • 学会为 JavaScript 库编写类型定义
  • 理解模块声明和全局类型声明
  • 掌握 DefinitelyTyped 和 `@types` 包的使用

1.2 为什么本章如此重要

不是所有的 JavaScript 库都自带 TypeScript 类型定义。当你使用一个纯 JavaScript 库时,TypeScript 会报类型错误。声明文件让你能够为这些库提供类型信息,享受完整的类型检查和代码补全。

即使你不为第三方库编写类型定义,理解声明文件的原理也能帮助你更好地使用 TypeScript——理解类型是如何工作的,理解为什么某些代码能编译而某些不能。

1.3 核心问题引导

.d.ts 文件和普通 .ts 文件有什么区别?

declare 关键字的作用是什么?它能声明哪些东西?

如何为一个没有类型定义的 JavaScript 库编写类型声明?

@types 包是什么?DefinitelyTyped 是如何工作的?

模块声明和全局声明有什么区别?


二、核心概念详解

2.1 声明文件基础

typescript
// math.d.ts
declare function add(a: number, b: number): number;
declare function multiply(a: number, b: number): number;

declare const PI: number;

declare class Calculator {
  constructor(initialValue?: number);
  add(n: number): Calculator;
  subtract(n: number): Calculator;
  result(): number;
}

2.2 模块声明

typescript
// lodash.d.ts
declare module "lodash" {
  export function chunk<T>(array: T[], size?: number): T[][];
  export function compact<T>(array: (T | null | undefined | false)[]): T[];
  export function flatten<T>(array: (T | T[])[]): T[];
  
  export function map<T, R>(
    collection: T[],
    iteratee: (value: T, index: number) => R
  ): R[];
  
  export function filter<T>(
    collection: T[],
    predicate: (value: T) => boolean
  ): T[];
}

2.3 全局类型声明

typescript
// global.d.ts
declare global {
  interface Window {
    myApp: {
      version: string;
      config: AppConfig;
    };
  }
  
  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: "development" | "production" | "test";
      API_URL: string;
      DATABASE_URL: string;
    }
  }
}

export {};

2.4 为 JavaScript 库编写类型

typescript
// types/event-emitter.d.ts
declare module "tiny-event-emitter" {
  type EventHandler = (...args: any[]) => void;
  
  export class EventEmitter {
    on(event: string, handler: EventHandler): this;
    off(event: string, handler: EventHandler): this;
    emit(event: string, ...args: any[]): boolean;
    once(event: string, handler: EventHandler): this;
    removeAllListeners(event?: string): this;
    listenerCount(event: string): number;
  }
  
  export default EventEmitter;
}

2.5 泛型声明

typescript
declare module "my-store" {
  export interface Store<T> {
    getState(): T;
    setState(partial: Partial<T>): void;
    subscribe(listener: (state: T) => void): () => void;
  }
  
  export function createStore<T>(initialState: T): Store<T>;
  
  export function useStore<T, R>(
    store: Store<T>,
    selector: (state: T) => R
  ): R;
}

三、实战案例

3.1 案例一:为 Express 中间件编写类型

typescript
declare module "express-rate-limiter" {
  import { Request, Response, NextFunction } from "express";
  
  interface RateLimitOptions {
    windowMs: number;
    max: number;
    message?: string | object;
    statusCode?: number;
    keyGenerator?: (req: Request) => string;
    skip?: (req: Request) => boolean;
    handler?: (req: Request, res: Response, next: NextFunction) => void;
  }
  
  export function rateLimit(options: RateLimitOptions): (
    req: Request,
    res: Response,
    next: NextFunction
  ) => void;
  
  export default rateLimit;
}

3.2 案例二:为 Web Worker 编写类型

typescript
// worker.d.ts
declare module "worker-loader!*" {
  class WebpackWorker extends Worker {
    constructor();
  }
  export default WebpackWorker;
}

declare class ImageProcessor {
  constructor();
  process(imageData: ImageData): Promise<ImageData>;
  terminate(): void;
}

declare namespace ImageProcessor {
  interface Options {
    width: number;
    height: number;
    filters: FilterType[];
  }
  
  type FilterType = "blur" | "sharpen" | "grayscale" | "sepia";
}

3.3 案例三:完整的库类型定义

typescript
declare module "simple-orm" {
  export interface ColumnOptions {
    primary?: boolean;
    autoIncrement?: boolean;
    nullable?: boolean;
    unique?: boolean;
    default?: any;
  }
  
  export interface TableOptions {
    tableName?: string;
    timestamps?: boolean;
  }
  
  export function Table(options?: TableOptions): ClassDecorator;
  export function Column(options?: ColumnOptions): PropertyDecorator;
  
  export class Repository<T> {
    findById(id: number | string): Promise<T | null>;
    findAll(): Promise<T[]>;
    find(where: Partial<T>): Promise<T[]>;
    create(data: Omit<T, "id">): Promise<T>;
    update(id: number | string, data: Partial<T>): Promise<T>;
    delete(id: number | string): Promise<boolean>;
    count(where?: Partial<T>): Promise<number>;
  }
  
  export function getRepository<T>(entity: new () => T): Repository<T>;
}

四、本章小结

声明文件:.d.ts 文件为 JavaScript 代码提供类型信息。

declare 关键字:声明变量、函数、类、模块等,不生成运行时代码。

模块声明:declare module "xxx" 为第三方模块提供类型。

全局声明:declare global 扩展全局类型。

DefinitelyTyped:社区维护的 @types 包仓库。


五、思考与练习

.d.ts 文件中的 declare 和普通 .ts 文件中的声明有什么区别?

如何为一个使用 CommonJS 的 JavaScript 库编写类型声明?

编写一个完整的 .d.ts 文件,为一个简单的工具库提供类型定义。


7/7声明文件
0%