第三方库类型

在 TypeScript 项目中使用第三方库时,需要类型声明来获得类型检查和智能提示。第三方库的类型来源有多种方式。

库自带类型声明

很多现代库自带类型声明文件。

{
  "name": "axios",
  "version": "1.0.0",
  "main": "index.js",
  "types": "index.d.ts"
}

types 字段指定类型声明文件的路径。安装库后自动获得类型支持。

import axios from "axios"

axios.get("/api/users").then((response) => {
  console.log(response.data)
})

DefinitelyTyped

DefinitelyTyped 是社区维护的类型声明仓库,提供 @types/xxx 包。

npm install lodash
npm install @types/lodash --save-dev

安装类型包后获得类型支持。

import _ from "lodash"

const result = _.chunk([1, 2, 3, 4], 2)
console.log(result)

const debounced = _.debounce(() => {
  console.log("防抖执行")
}, 300)

查找类型声明

查找库的类型声明:

  1. 检查库的 package.json 是否有 typestypings 字段
  2. 搜索 @types/库名
  3. 查看 DefinitelyTyped 仓库
  4. 自己编写声明文件
npm info axios types
npm search @types/lodash

安装类型声明

安装类型声明包:

npm install @types/node --save-dev
npm install @types/react --save-dev
npm install @types/jest --save-dev

类型声明包应该作为开发依赖安装。

类型声明版本

类型声明包的版本应该与库的版本匹配。

npm install lodash@4.17.21
npm install @types/lodash@4.14.0 --save-dev

版本不匹配可能导致类型错误。

缺少类型声明

当库没有类型声明时,可以:

  1. 创建自定义声明文件
  2. 使用 any 类型(不推荐)
  3. 向 DefinitelyTyped 贡献类型

创建自定义声明文件:

declare module "my-library" {
  export function doSomething(value: string): number
  export const version: string
}

类型声明覆盖

可以覆盖库的类型声明。

import { User } from "my-library"

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

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com",
  age: 25
}

类型声明配置

tsconfig.json 中配置类型声明。

{
  "compilerOptions": {
    "typeRoots": ["./types", "./node_modules/@types"],
    "types": ["node", "jest"]
  }
}

typeRoots 指定类型声明的查找位置,types 指定要包含的类型声明。

常用类型声明包

常用的类型声明包:

npm install @types/node --save-dev
npm install @types/react --save-dev
npm install @types/react-dom --save-dev
npm install @types/express --save-dev
npm install @types/jest --save-dev
npm install @types/jquery --save-dev

实际应用

在项目中使用多个第三方库。

import axios from "axios"
import _ from "lodash"
import dayjs from "dayjs"

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

async function fetchUsers(): Promise<User[]> {
  const response = await axios.get<User[]>("/api/users")
  return response.data
}

function processUsers(users: User[]): User[] {
  return _.filter(users, (user) => user.email.includes("@"))
}

function formatDate(date: string): string {
  return dayjs(date).format("YYYY-MM-DD")
}

async function main() {
  const users = await fetchUsers()
  const validUsers = processUsers(users)

  validUsers.forEach((user) => {
    console.log(`${user.name} - ${formatDate(user.createdAt)}`)
  })
}

main()

小结

第三方库的类型声明可以来自库自带或 DefinitelyTyped。@types/xxx 包是社区维护的类型声明。安装类型声明包后获得类型检查和智能提示。当库没有类型声明时,可以创建自定义声明文件。合理配置类型声明可以提高开发效率。