TypeScript 声明文件

TypeScript声明文件全攻略 – 小白必备

TypeScript声明文件知识点汇总

编程小白也能完全理解的TypeScript声明文件指南

什么是声明文件?

声明文件(Declaration File)是TypeScript的核心概念之一,文件扩展名通常为.d.ts。你可以把它想象成一份”说明书”或者”类型字典”——它告诉TypeScript某个JavaScript代码库有哪些变量、函数、类等,以及它们的具体类型。

现实生活比喻

想象你买了一台进口家电,但说明书是外语的看不懂。声明文件就像一份中文翻译,告诉你每个按钮的功能和使用方法,让你能正确使用这台家电。

JavaScript文件 (实际代码)
// mathUtils.js
function add(a, b) {
  return a + b;
}

const PI = 3.14159;
声明文件 (类型说明)
// mathUtils.d.ts
declare function add(a: number, b: number): number;

declare const PI: number;

为什么需要声明文件?

声明文件解决了TypeScript的一个核心问题:当使用纯JavaScript编写的第三方库时,TypeScript无法获取类型信息。

核心价值: 声明文件让TypeScript认识非TypeScript编写的代码,提供类型检查和智能提示,同时不需要修改原始JS代码。

主要作用:

  • 类型检查 – 防止传入错误类型的参数
  • 智能提示 – 编辑器提供自动补全和API文档提示
  • 代码可维护性 – 明确API的使用方式和使用约束
  • 兼容性 – 让现有JavaScript项目逐步迁移到TypeScript

注意: 声明文件只包含类型声明,不包含具体实现。它就像是代码的”类型蓝图”。

声明文件类型

根据使用场景,声明文件主要有三种类型:

1. 全局声明文件

当你有一个全局可用的库(直接在<script>标签中引入)时使用。

// global.d.ts
declare var myGlobalLib: {
  version: string;
  doSomething(): void;
};
2. 模块声明文件

当使用模块化库(通过import引入)时使用。

// my-module.d.ts
declare module “my-module” {
  export function doSomething(): void;
  export const someValue: number;
}
3. 扩展声明文件

当需要为已有库添加额外功能时使用。

// jquery.extensions.d.ts
declare namespace JQuery {
  interface Static {
    newPlugin(): void;
  }
}

基本语法结构

声明文件的核心关键字是declare,它告诉TypeScript:”这个东西存在,并且类型是这样的”。

// 基本结构
declare var name: type; // 声明变量
declare function fn(…args): returnType; // 声明函数
declare class ClassName { … } // 声明类
declare namespace Namespace { … } // 声明命名空间
declare module “module-name” { … } // 声明模块
interface InterfaceName { … } // 声明接口
type TypeName = …; // 声明类型别名

关键点: 在声明文件中,所有顶级声明默认都是全局的(除非在模块中声明)。如果文件中有importexport,它会被视为模块声明文件。

声明变量

声明全局变量或模块中的变量:

// 声明全局变量
declare const VERSION: string;
declare let config: {
  debug: boolean;
  apiUrl: string;
};

// 在模块中声明变量
declare module “my-module” {
  export const defaultTimeout: number;
}

声明函数

声明全局函数或模块中的函数:

// 声明全局函数
declare function calculate(x: number, y: number): number;

// 声明带有可选参数和重载的函数
declare function createElement(tag: string): HTMLElement;
declare function createElement(tag: string, attributes: object): HTMLElement;

// 声明模块中的函数
declare module “math-utils” {
  export function sum(…numbers: number[]): number;
}

声明类

声明类及其属性和方法:

declare class Person {
  // 构造函数
  constructor(name: string, age: number);

  // 属性
  name: string;
  age: number;

  // 方法
  greet(): string;

  // 静态属性
  static species: string;

  // 静态方法
  static createDefault(): Person;
}

提示: 在声明类时,只需要声明公共成员(public),私有成员(private)通常不需要在声明文件中写出,因为外部代码无法访问它们。

声明接口

接口用来描述对象的形状,在声明文件中非常常用:

// 基本接口声明
interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

// 带有可选属性和方法的接口
interface Config {
  apiUrl: string;
  timeout?: number; // 可选属性
  onSuccess?(): void; // 可选方法
}

// 使用接口声明函数参数
declare function createUser(user: User): void;

模块声明

用于描述通过模块系统(如ES6模块、CommonJS)加载的代码:

// 声明整个模块
declare module “my-library” {
  export function doSomething(): void;
  export const version: string;
  export interface Options { … }
}

// 声明UMD模块(同时支持多种模块系统)
declare module “my-umd-lib” {
  export = myLib; // 兼容CommonJS
}

declare namespace myLib {
  function doSomething(): void;
}

全局声明

当某些变量、函数或类在全局范围可用时使用:

// 声明全局变量
declare const APP_VERSION: string;

// 声明全局函数
declare function logMessage(message: string): void;

// 声明全局类
declare class Logger {
  log(message: string): void;
}

// 防止声明文件变成全局声明
export {}; // 添加空导出使其成为模块

全局声明最佳实践: 尽量避免使用全局声明以防止污染全局命名空间。如果必须使用,最好在一个统一的全局声明文件中管理所有全局声明。

命名空间

命名空间用于组织相关代码,避免命名冲突:

// 声明命名空间
declare namespace MyLibrary {
  function utilityFn(): void;
  const version: string;

  // 嵌套命名空间
  namespace MathUtils {
    function sum(a: number, b: number): number;
  }
}

// 使用
MyLibrary.utilityFn();
MyLibrary.MathUtils.sum(1, 2);

注意: 在ES6模块普及后,命名空间的使用逐渐减少。现代TypeScript项目更推荐使用模块导入导出。

泛型声明

泛型让类型像参数一样可重用:

// 泛型接口
interface Response<T> {
  data: T;
  status: number;
  message: string;
}

// 泛型函数
declare function identity<T>(arg: T): T;

// 泛型类
declare class Queue<T> {
  push(item: T): void;
  pop(): T | undefined;
}

// 使用示例
const numResponse: Response<number> = {
  data: 42,
  status: 200,
  message: “Success”
};

高级技巧

1. 扩展已有声明

// 扩展全局Window对象
declare global {
  interface Window {
    myCustomProp: string;
  }
}

// 扩展已有模块
declare module “existing-module” {
  export interface ExtendedInterface {
    newMethod(): void;
  }
}

2. 条件类型

type NonNullable<T> = T extends null | undefined ? never : T;
type Flatten<T> = T extends Array<infer U> ? U : T;

3. 类型推导

// 推断函数返回类型
declare function getValue<T>(): T;
type ValueType = ReturnType<typeof getValue>; // T

// 推断函数参数类型
declare function setValue<T>(value: T): void;
type ParamType = Parameters<typeof setValue>[0]; // T

发布声明文件

当你的库使用TypeScript编写时,会自动生成声明文件。纯JavaScript库需要手动编写声明文件。

发布方式:

1. 与npm包一起发布

package.json中指定:

{
  “name”: “my-library”,
  “version”: “1.0.0”,
  “types”: “dist/index.d.ts”,
  “main”: “dist/index.js”
}
2. 发布到DefinitelyTyped

为没有内置类型声明的库提供类型:

  • 在GitHub创建PR到DefinitelyTyped仓库
  • 用户通过npm install @types/library-name安装
  • 适用于维护者不提供类型声明的情况

最佳实践: 优先选择将声明文件和库一起发布的方式。对于无法控制的第三方库,使用@types包。

TypeScript声明文件知识点汇总 © 2023 – 编程小白的TypeScript学习指南

声明文件是TypeScript生态系统的关键部分,掌握它将大大提升你的TS开发效率!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部