返回笔记列表
01 · NOTES / WebGIS 开发

第 39 节 · 声明与模块(d.ts / declare / @types)

2026 年 9 月 1 日

第 39 节 · 声明与模块(d.ts / declare / @types)

📌 版本信息:基于 TypeScript 5.x(2026-08-29 核对) 📚 来源:TS 手册 · Declarations阮一峰 TS 教程 · declareDefinitelyTyped

一、这一节的目标(模块 02 最后一节)

  1. 理解 .d.ts 是什么:只有类型没有实现的"说明书"
  2. 掌握 declare 家族:全局变量、模块声明、环境声明
  3. 说清 @types/xxx 生态的运作方式
  4. 会给一个无类型的旧 JS 库手写最小声明
  5. 理解 import type 与编译期擦除

二、.d.ts:类型说明书

lodash.js     ← 运行时实现(JS)
lodash.d.ts   ← 类型说明书(没有函数体,只有签名)
// my-lib.d.ts 的样子:注意没有实现体
export interface Options { zoom: number; basemap?: string }
export function init(el: HTMLElement, opts: Options): void;
export function destroy(): void;

TS 编译时读 .d.ts 做检查,运行时加载 .js 真身——两套文件,各管一摊。你用的每个现代库(React/Leaflet/OL)都带着这套"说明书",所以编辑器才有完美补全。


三、declare 家族

// ① 全局变量声明:script 标签注入的东西(如 <script>window.APP_CONFIG</script>)
declare const APP_CONFIG: { apiUrl: string; mapKey: string };
APP_CONFIG.apiUrl;   // ✅ 类型可用(运行时它真的在 window 上——声明只是告诉 TS)

// ② 全局函数(同上场景)
declare function report(msg: string): void;

// ③ 模块声明:给"没有类型的第三方库"补最小说明书
declare module 'old-leaflet-plugin' {
  export function addTo(map: unknown): void;
  const _default: { version: string };
  export default _default;
}
// 放到项目里的 *.d.ts(如 src/globals.d.ts),TS 自动读取

// ④ 环境声明文件的组织:项目里建 src/types/globals.d.ts 收纳全局 declare

⚠️ declare 的东西必须运行时真的存在——declare const APP_CONFIG 后页面却没注入它,运行时照样 undefined。TS 不负责兑现,只负责"相信你"。


四、@types 生态

# 主流库自带类型(无需额外装):react、vue、leaflet、openlayers…
# 老库类型在 DefinitelyTyped 社区仓库(发布为 @types/xxx):
npm install -D @types/lodash

查找顺序(TS 自动解析):库自带的 types 字段 → @types/lodash 包。看 package.json 里 types/typings 字段就知道库是否自带。

有的库要关类型:// @ts-ignore(下一行豁免)→ // @ts-expect-error(更好:如果这行其实没错误会反过来报错,防止遗留)。


五、import type 与擦除

// 值导入:运行时真的加载
import { fetchQuakes } from './quake.js';

// 纯类型导入:只用于类型检查,编译后完全消失
import type { QuakeCollection } from './quake.js';

// 混合:inline type 修饰
import { fetchQuakes, type QuakeFeature } from './quake.js';

为什么用 import type:①语义清晰——它只参与编译期;②彻底避免"循环 import 运行时报 undefined"的坑(两个模块只互用对方类型时,用 import type 打破运行时环);③构建工具能放心 tree-shake。


六、动手收尾(融进 C-02b)

综合项目里会实践本节三件事:

  1. src/types/geojson.d.ts:把 GeoJSON 的类型集中为环境声明(或直接 module 内 interface,看规模)
  2. src/types/globals.d.ts:声明演示用 declare const USGS_FEED: string
  3. 全项目 import type 化:类型引用一律 type 导入

七、自测题

  1. .d.ts 和 .js 的分工?
  2. declare const X: T 保证 X 运行时存在吗?
  3. @types/lodash 是谁维护的?库自带类型时还要装吗?
  4. @ts-expect-error@ts-ignore 好在哪?
  5. 两个模块互相只用对方的类型时,用什么导入避免运行时循环?

参考答案

  1. .d.ts 只有类型签名供编译器检查;.js 是运行时实现。
  2. 不保证——声明只管编译期"相信你",运行时必须真的存在。
  3. DefinitelyTyped 社区;库自带(package.json 有 types 字段)时不用装。
  4. 若被标记行实际没有错误,@ts-expect-error 自己会报错——提醒你删掉过时的豁免;@ts-ignore 会永远静默。
  5. import type——类型在编译期擦除,不产生运行时依赖边,循环环自然消失。

八、🎉 模块 02 · Web 基础 全部 39 节完结

阶段一(0127 HTML/CSS/JS/TS/Tailwind)+ 阶段二(2839 原理精通)全部产出。

收尾三件事(进入下一模块前):

  1. 综合项目 C-02a 个人主页:纯 HTML/CSS 响应式三页站(学完 08 就能做,现在做正好用上 Tailwind)
  2. 综合项目 C-02b 地震数据面板 TS 版:以 23-ts-demo 的 quake.ts 为数据模块起点 + USGS 真实数据 + Tailwind 界面
  3. 两个项目做完在 学习计划.md 打卡,然后进入 模块 03 · React 与 Next.js(章程已备好,27 节)
TAGSweb