TypeScript声明文件知识点汇总
什么是声明文件?
声明文件(Declaration File)是TypeScript的核心概念之一,文件扩展名通常为.d.ts
。你可以把它想象成一份”说明书”或者”类型字典”——它告诉TypeScript某个JavaScript代码库有哪些变量、函数、类等,以及它们的具体类型。
现实生活比喻
想象你买了一台进口家电,但说明书是外语的看不懂。声明文件就像一份中文翻译,告诉你每个按钮的功能和使用方法,让你能正确使用这台家电。
function add(a, b) {
return a + b;
}
const PI = 3.14159;
declare function add(a: number, b: number): number;
declare const PI: number;
为什么需要声明文件?
声明文件解决了TypeScript的一个核心问题:当使用纯JavaScript编写的第三方库时,TypeScript无法获取类型信息。
核心价值: 声明文件让TypeScript认识非TypeScript编写的代码,提供类型检查和智能提示,同时不需要修改原始JS代码。
主要作用:
- 类型检查 – 防止传入错误类型的参数
- 智能提示 – 编辑器提供自动补全和API文档提示
- 代码可维护性 – 明确API的使用方式和使用约束
- 兼容性 – 让现有JavaScript项目逐步迁移到TypeScript
注意: 声明文件只包含类型声明,不包含具体实现。它就像是代码的”类型蓝图”。
声明文件类型
根据使用场景,声明文件主要有三种类型:
当你有一个全局可用的库(直接在<script>标签中引入)时使用。
declare var myGlobalLib: {
version: string;
doSomething(): void;
};
当使用模块化库(通过import引入)时使用。
declare module “my-module” {
export function doSomething(): void;
export const someValue: number;
}
当需要为已有库添加额外功能时使用。
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 = …; // 声明类型别名
关键点: 在声明文件中,所有顶级声明默认都是全局的(除非在模块中声明)。如果文件中有import
或export
,它会被视为模块声明文件。
声明变量
声明全局变量或模块中的变量:
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;
}
声明类
声明类及其属性和方法:
// 构造函数
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. 扩展已有声明
declare global {
interface Window {
myCustomProp: string;
}
}
// 扩展已有模块
declare module “existing-module” {
export interface ExtendedInterface {
newMethod(): void;
}
}
2. 条件类型
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库需要手动编写声明文件。
发布方式:
在package.json
中指定:
“name”: “my-library”,
“version”: “1.0.0”,
“types”: “dist/index.d.ts”,
“main”: “dist/index.js”
}
为没有内置类型声明的库提供类型:
- 在GitHub创建PR到DefinitelyTyped仓库
- 用户通过
npm install @types/library-name
安装 - 适用于维护者不提供类型声明的情况
最佳实践: 优先选择将声明文件和库一起发布的方式。对于无法控制的第三方库,使用@types包。