编写声明文件

编写声明文件是为 JavaScript 代码添加类型支持的重要技能。通过编写声明文件,可以让 JavaScript 库获得 TypeScript 的类型检查和智能提示。

基本结构

声明文件的基本结构包含各种类型声明。

declare const version: string

declare function greet(name: string): string

declare class User {
  constructor(name: string)
  name: string
  greet(): string
}

declare interface Config {
  apiKey: string
  baseUrl?: string
}

声明变量

使用 declare constdeclare letdeclare var 声明变量。

declare const API_URL: string
declare let debug: boolean
declare var jQuery: (selector: string) => any

声明函数

使用 declare function 声明函数。

declare function log(message: string): void

declare function fetch(
  url: string,
  options?: {
    method?: string
    headers?: Record<string, string>
    body?: string
  }
): Promise<Response>

函数声明支持重载。

declare function createElement(tag: "div"): HTMLDivElement
declare function createElement(tag: "span"): HTMLSpanElement
declare function createElement(tag: string): HTMLElement

声明类

使用 declare class 声明类。

declare class User {
  constructor(name: string)
  readonly name: string
  private id: number
  greet(): string
  static create(name: string): User
}

类声明可以包含构造函数、属性、方法和静态成员。

声明接口

使用 declare interface 或直接 interface 声明接口。

interface User {
  id: number
  name: string
  email: string
}

interface Config {
  apiKey: string
  baseUrl?: string
  timeout?: number
}

声明类型别名

使用 declare type 或直接 type 声明类型别名。

type ID = string | number

type EventHandler = (event: Event) => void

type Status = "active" | "inactive" | "pending"

声明枚举

使用 declare enum 声明枚举。

declare enum Status {
  Active = "ACTIVE",
  Inactive = "INACTIVE",
  Pending = "PENDING"
}

声明模块

使用 declare module 声明模块。

declare module "my-library" {
  export interface Config {
    apiKey: string
    debug?: boolean
  }

  export function init(config: Config): void
  export function track(event: string, data?: any): void

  const version: string
  export default version
}

模块声明可以包含导出和默认导出。

声明全局

使用 declare global 扩展全局命名空间。

declare global {
  interface Window {
    mySDK: {
      init: (config: { apiKey: string }) => void
      track: (event: string) => void
    }
  }

  const API_URL: string
}

export {}

注意需要 export {} 使文件成为模块。

声明命名空间

使用 declare namespace 声明命名空间。

declare namespace MyLib {
  interface User {
    id: number
    name: string
  }

  function createUser(name: string): User

  namespace Utils {
    function formatDate(date: Date): string
  }
}

模块扩展

使用 declare module 扩展现有模块。

import { User } from "my-library"

declare module "my-library" {
  interface User {
    age: number
    email: string
  }
}

扩展后的类型会合并到原有类型。

文件扩展

使用三斜线指令引用其他声明文件。

/// <reference path="./types/jquery.d.ts" />
/// <reference path="./types/lodash.d.ts" />

declare function $(selector: string): any

实际应用

为一个简单的 SDK 编写声明文件。

declare module "analytics-sdk" {
  export interface Config {
    trackingId: string
    debug?: boolean
    bufferSize?: number
  }

  export interface Event {
    name: string
    timestamp: number
    data?: Record<string, any>
  }

  export interface Analytics {
    init(config: Config): void
    track(eventName: string, data?: Record<string, any>): void
    identify(userId: string, traits?: Record<string, any>): void
    flush(): Promise<void>
  }

  const analytics: Analytics
  export default analytics
}

使用时获得完整的类型支持。

import analytics, { Config, Event } from "analytics-sdk"

const config: Config = {
  trackingId: "UA-XXXXX-Y",
  debug: true,
  bufferSize: 100
}

analytics.init(config)
analytics.track("page_view", { page: "/home" })
analytics.identify("user-123", { name: "张三" })

async function flushEvents() {
  await analytics.flush()
}

flushEvents()

小结

编写声明文件使用 declare 关键字声明各种类型。可以声明变量、函数、类、接口、类型别名、枚举等。declare module 用于声明模块,declare global 用于扩展全局命名空间,declare namespace 用于声明命名空间。声明文件让 JavaScript 库获得 TypeScript 的类型支持。