首页 / TypeScript 入门教程 / 全局声明

TypeScript 入门教程

全局声明

本教程共 80 篇 · 第 59 篇 · 更新于 2026-08-10 · 约 9 分钟阅读

TypeScriptTypeScript 入门教程declare全局声明declare globaldeclare module

本节目标:掌握 declare 关键字的用法——声明全局变量、函数、类与命名空间。理解 declare global 如何从模块内部增强全局作用域,以及 declare module "*.css" 这类通配模块声明的作用。

TypeScript 的类型安全建立在”编译器知道每个值是什么类型”的基础上。但你用的不都是 TypeScript 写的代码——全局引入的 jQuery、通过 CDN 加载的第三方库、或者打包工具处理后的 CSS 和图片,TypeScript 默认都不认识。declare 关键字就是用来告诉 TypeScript:“这个变量确实存在,它的类型是这样的。“

declare 关键字的本质

declare 声明的是环境声明(ambient declaration)——它描述”存在什么”,不生成任何 JavaScript 代码。编译后,所有 declare 语句都会被删除。你可以把它理解为给 TypeScript 编译器写的”承诺书”。

// 声明一个全局变量
declare var DEBUG: boolean;

// 声明一个全局函数
declare function trackEvent(eventName: string, data?: object): void;

// 声明一个全局类
declare class UserAgent {
  readonly browser: string;
  readonly version: string;
}

// 声明一个全局命名空间
declare namespace AppConfig {
  const apiUrl: string;
  const maxRetries: number;
}

上面这些声明不会产生任何 JS 代码。但它们让 TypeScript 知道了在运行时会有 DEBUG 变量、trackEvent 函数、UserAgent 类和 AppConfig 对象——不会再报”找不到名称”的错误。

声明文件 vs 声明语句

declare 可以写在 .ts 源文件里,也可以写在 .d.ts 声明文件里。两者的区别:

// app.ts——源文件里的 declare 语句
declare var API_KEY: string;
console.log(API_KEY); // 类型安全
// globals.d.ts——声明文件,全是 declare
declare var API_KEY: string;
declare var APP_VERSION: string;
declare function log(message: string): void;

实际项目里,全局声明通常放在单独的 .d.ts 文件:一处声明,整个项目可用。混在源文件里的 declare 容易散落各地,维护起来很痛苦。

声明全局变量、函数和类

三种形式分别对应三种运行时实体:

// 变量:用 var / let / const
declare var globalConfig: {
  debug: boolean;
  env: "dev" | "prod";
};
declare let currentUser: { name: string } | null;
declare const MAX_SIZE: 1024;

// 函数:可以有重载
declare function $(selector: string): HTMLElement;
declare function $(selector: string, context: HTMLElement): HTMLElement;

// 类:只声明公共接口,不写实现
declare class EventBus {
  on(event: string, handler: Function): void;
  emit(event: string, ...args: unknown[]): void;
}

declare var / declare let / declare const 的语义和它们在常规代码里一样——const 声明的就是只读的。

declare global {}——从模块内部增强全局作用域

这是 TypeScript 里一个很精巧的设计。模块文件天然有独立作用域,但有时你需要从模块内部往全局加东西。举个例子:

// app.ts(这是一个模块,因为有顶层 export)
export function initApp() {
  console.log("App started");
}

app.ts 里写 declare var DEBUG: boolean 会创建一个模块作用域内的声明,不会影响全局。但如果你真想给全局加一个属性,用 declare global

// app.ts
export function initApp() {
  window.myApp = { loaded: true };
}

declare global {
  interface Window {
    myApp: { loaded: boolean };
  }
}

declare global 块里的所有声明都会作用到全局空间。上面的代码让 window.myApp 有了类型——任何文件里写 window.myApp 都不会报错。

Tip

declare global 只在模块文件(有顶层 import 或 export 的文件)里有效。脚本文件本身就处于全局作用域,用不着 declare global

常见的 declare global 场景:

// 给内置类型打补丁
declare global {
  interface Array<T> {
    toSorted(): T[];
  }

  interface String {
    trimStart(): string;
  }

  namespace NodeJS {
    interface ProcessEnv {
    NODE_ENV: "development" | "production";
      API_URL: string;
    }
  }
}

export {}; // 确保这个文件被当作模块

注意末尾的 export {}declare global 需要在模块文件里才能生效,如果文件里没有 import/export,加一个空的 export {} 把文件变成模块即可。

declare module——通配模块声明

打包工具可以导入非 JS 资源——CSS、图片、JSON、SVG。这些文件 TypeScript 不认识,import styles from "./app.css" 会报类型错误。

解决方案是通配模块声明(wildcard module declaration):

// types/assets.d.ts
declare module "*.css" {
  const content: Record<string, string>;
  export default content;
}

declare module "*.png" {
  const src: string;
  export default src;
}

declare module "*.svg" {
  import type { FC, SVGProps } from "react";
  const Component: FC<SVGProps<SVGSVGElement>>;
  export default Component;
}

这样在任何 .ts.tsx 文件里导入 *.css*.png*.svg,TypeScript 都能给出正确的类型。

declare module 不止用于通配符。你也可以声明一个不存在的模块的类型:

declare module "virtual:config" {
  const config: {
    apiUrl: string;
    features: string[];
  };
  export default config;
}

Vite 里的虚拟模块就是这样——模块不在文件系统里,由插件在运行时生成。declare module 让 TypeScript 认识了它。

让 declare 文件被 TypeScript 发现

全局 .d.ts 文件需要被 TypeScript 纳入编译范围。TS 7.0 默认 types: [],意味着不会自动加载 node_modules/@types/*。你需要显式配置:

{
  "compilerOptions": {
    "types": ["node"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts"]
}

项目自己的 .d.ts 文件放在 src 目录下,通过 include 字段让编译器找到。@types/* 包通过 types 字段逐个引入——这和 TS 6.x 以前”自动加载所有 @types” 的行为不一样,是 7.0 的破坏性变更之一。

小结

declare 是 TypeScript 和外部 JavaScript 世界对话的桥梁。声明全局变量、函数、类让编译器认识那些不在 TypeScript 代码里的东西;declare global 从模块内部扩展全局作用域;declare module 让非 JS 资源和虚拟模块也有类型支持。这些声明最终都不会出现在编译产物里——它们纯粹是给编译器看的元信息。