TypeScript 声明文件
声明文件(Declaration Files)用于为 JavaScript 代码提供类型定义,文件扩展名为 .d.ts。它们让 TypeScript 能够理解 JavaScript 库的类型,提供类型检查和智能提示。
为什么需要声明文件?
当使用 JavaScript 编写的第三方库时,TypeScript 无法知道这些库的类型信息。声明文件为这些库提供了类型定义。
ts
// 没有声明文件:TypeScript 不知道 jQuery 的类型
$("#myElement").hide(); // ❌ 错误:找不到名称 "$"
// 有了声明文件:TypeScript 知道 jQuery 的类型
$("#myElement").hide(); // ✅ 正确声明文件类型
全局声明
为全局变量、函数或类提供类型声明。
ts
// global.d.ts
declare var jQuery: (selector: string) => any;
declare function $(): void;
declare const API_URL: string;
// 使用
jQuery("#app");
$();
console.log(API_URL);模块声明
为模块提供类型声明。
ts
// my-module.d.ts
declare module "my-module" {
export function doSomething(): void;
export const version: string;
}
// 使用
import { doSomething, version } from "my-module";命名空间声明
使用命名空间组织类型声明。
ts
// jquery.d.ts
declare namespace jQuery {
interface AjaxSettings {
url: string;
method?: string;
data?: any;
}
function ajax(settings: AjaxSettings): void;
}
// 使用
jQuery.ajax({
url: "/api/data",
method: "GET"
});创建声明文件
为 JavaScript 文件创建声明文件
假设有一个 JavaScript 文件 math.js:
js
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export const PI = 3.14159;对应的声明文件 math.d.ts:
ts
// math.d.ts
export function add(a: number, b: number): number;
export function subtract(a: number, b: number): number;
export const PI: number;为第三方库创建声明文件
为没有类型定义的第三方库创建声明文件。
ts
// custom-library.d.ts
declare module "custom-library" {
export interface Config {
apiKey: string;
timeout?: number;
}
export class Client {
constructor(config: Config);
request(url: string): Promise<any>;
}
export function init(config: Config): Client;
}声明合并
TypeScript 允许将多个同名的声明合并为一个。
接口合并
ts
interface User {
name: string;
}
interface User {
age: number;
}
// 合并后的 User 接口包含 name 和 age
const user: User = {
name: "John",
age: 30
};命名空间合并
ts
namespace MyLib {
export function func1(): void;
}
namespace MyLib {
export function func2(): void;
}
// 合并后 MyLib 包含 func1 和 func2
MyLib.func1();
MyLib.func2();命名空间与类合并
ts
class Album {
label: Album.AlbumLabel;
}
namespace Album {
export class AlbumLabel {
name: string;
}
}模块扩展
扩展已有模块的类型定义。
扩展第三方模块
ts
// 扩展 express 模块
declare module "express" {
interface Request {
user?: {
id: string;
name: string;
};
}
}
// 使用
import express from "express";
const app = express();
app.use((req, res, next) => {
req.user = { id: "1", name: "John" };
next();
});扩展全局类型
ts
// 扩展 Window 对象
declare global {
interface Window {
myCustomProperty: string;
}
}
// 使用
window.myCustomProperty = "value";类型声明文件的位置
项目内声明文件
- 与源文件同目录:
src/utils.ts→src/utils.d.ts types目录:types/custom.d.ts@types目录:@types/custom/index.d.ts
全局声明文件
在 tsconfig.json 中配置:
json
{
"compilerOptions": {
"typeRoots": ["./types", "./node_modules/@types"]
},
"include": ["src/**/*", "types/**/*.d.ts"]
}三斜线指令
三斜线指令用于声明文件之间的依赖关系。
///
引用另一个声明文件包。
ts
/// <reference types="node" />
/// <reference types="express" />
import * as http from "http";
import express from "express";///
引用另一个声明文件。
ts
/// <reference path="./types.d.ts" />常用声明文件模式
函数重载
ts
declare function createElement(tag: "div"): HTMLDivElement;
declare function createElement(tag: "span"): HTMLSpanElement;
declare function createElement(tag: string): HTMLElement;泛型声明
ts
declare interface Array<T> {
myCustomMethod(): T[];
}条件类型
ts
declare type NonNullable<T> = T extends null | undefined ? never : T;发布声明文件
方式一:与源码一起发布
如果库是用 TypeScript 编写的,编译时会自动生成 .d.ts 文件。
json
// tsconfig.json
{
"compilerOptions": {
"declaration": true, // 生成声明文件
"declarationDir": "./dist/types" // 声明文件输出目录
}
}方式二:发布到 @types
为没有类型定义的库创建声明文件并发布到 @types。
- Fork DefinitelyTyped
- 创建类型定义文件
- 提交 Pull Request
方式三:在 package.json 中指定
json
{
"name": "my-package",
"version": "1.0.0",
"types": "./dist/index.d.ts",
"main": "./dist/index.js"
}实际示例
为 jQuery 创建声明文件
ts
// jquery.d.ts
declare namespace jQuery {
interface Selector {
(selector: string): jQueryInstance;
}
interface jQueryInstance {
hide(): jQueryInstance;
show(): jQueryInstance;
html(content?: string): string | jQueryInstance;
on(event: string, handler: Function): jQueryInstance;
}
interface AjaxOptions {
url: string;
method?: string;
data?: any;
success?: (data: any) => void;
error?: (error: any) => void;
}
function ajax(options: AjaxOptions): void;
}
declare const $: jQuery.Selector;
declare const jQuery: jQuery.Selector;为自定义工具函数创建声明文件
ts
// utils.d.ts
export interface FormatOptions {
date?: boolean;
currency?: boolean;
}
export function format(value: any, options?: FormatOptions): string;
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void;最佳实践
- 使用严格类型:尽可能使用具体的类型,避免
any - 提供完整定义:为所有导出的 API 提供类型定义
- 使用 JSDoc 注释:为类型定义添加文档注释
- 测试类型定义:确保类型定义与实际代码匹配
- 保持更新:当库更新时,及时更新类型定义
最后更新:2025年