夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • TypeScript基础

  • TypeScript进阶

    • 声明合并
    • declare声明
    • TS的(.d.ts)文件
      • 一、 概述
      • 二、 什么是“.d.ts” 文件
        • 2.1 DefinitelyTyped
        • 2.2 Typings
        • 2.3 @Types
        • 2.4 *.d.ts和@types关系
        • 2.5 declare 和 export
      • 三、 编写语法
        • 3.1 全局类型
        • 3.2 模块化的全局变量
        • 3.3 模块化(CommonJS)
        • 3.4 ES6的模块化方式(import export)
        • 3.5 UMD
        • 3.6 其他
      • 四、.d.ts声明文件模板
        • 4.1 查看库结构
        • 4.2 类型文件测试
        • 4.3 拓展插件声明模板
        • 4.4 拓展全局模板
      • 五、案例
    • 命名空间namespace
    • 理解TS模块
  • TS 从零实现 axios

  • 《TypeScript》
  • TypeScript进阶
夜猫子
2023-03-02
目录

TS的(.d.ts)文件

# 一、 概述

随着前端技术的不断发展,TypeScript(简称:TS)已经在逐步取代JavaScript(简称:JS),尤其在以Vue3使用TS重构后,TS更是成为前端框架编写的主力语言。

  • 在使用TS的时候,最大的一个好处就是可以给JS各种类型约束,使得JS能够完成静态代码分析,推断代码中存在的类型错误或者进行类型提示

  • TS完成类型推断,需要事先知道变量的类型,如果我们都是用TS书写代码,并且给变量都指定了明确的类型,这时TS可以很好的完成类型推断工作

  • 但是有时,我们不免会引入外部的 JS库,这时TS就对引入的JS文件里变量的具体类型不明确了,为了告诉TS变量的类型,因此就有了.d.ts (d即declare),ts的声明文件。

    即 .d.ts 一般是用来描述没有定义类型的 js 的。

笔记

但是也不是说创建了.d.ts文件,里面声明的东西就能生效了,毕竟归根到底也是.ts文件,需要预编译,所以需要在tsconfig.json文件里面的include数组里面添加这个文件。

# 二、 什么是“.d.ts” 文件

基于 Typescript 开发的时候,很麻烦的一个问题就是类型定义。导致在编译的时候,经常会看到一连串的找不到类型的提示。“d.ts”文件用于为 TypeScript 提供有关用 JavaScript 编写的 API 的类型信息。简单讲,就是你可以在 ts 中调用的 js 的声明文件。TS的核心在于静态类型,我们在编写 TS 的时候会定义很多的类型,但是主流的库都是 JS编写的,并不支持类型系统。这个时候你不能用TS重写主流的库,这个时候我们只需要编写仅包含类型注释的 d.ts 文件,然后从您的 TS 代码中,可以在仍然使用纯 JS 库的同时,获得静态类型检查的 TS 优势。在此期间,解决的方式经过了许多的变化,从 DefinitelyTyped (opens new window) 到 typings (opens new window)。最后是 @types (opens new window)。在 Typescript 2.0 之后,推荐使用 @types (opens new window) 方式。

# 2.1 DefinitelyTyped

多数来自 javascript 的库是没有 TypeScript 类型定义的。为了解决这个问题,DefinitelyTyped (opens new window) 被创建出来,它提供了多数流行的脚本库的 TypeScript 定义,你可以使用名为 tsd (opens new window) 的一个工具来管理它。在 Typescript 2.0 中使用 @type 类型定义,这种方式已经不推荐使用。

  • 安装tsd工具
npm install tsd -g
# 或
yarn global add tsd 
1
2
3
  • 通过工具安装定义库
# 安装jquery定义库
tsd install jquery --save
1
2
  • 配置 如果提供了 --save 参数,它会创建一个名为 tsd.json 的配置文件来保存所管理的类型定义包。
{
    "version": "v4",
    "repo": "DefinitelyTyped/DefinitelyTyped",
    "ref": "master",
    "path": "typings",
    "bundle": "typings/tsd.d.ts",
    "installed": {
        "node/node.d.ts": {
            "commit": "6834f97fb33561a3ad40695084da2b660efaee29"
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

以后,直接使用tsd install就可以安装定义在配置文件中的所有的包了。

# 2.2 Typings

Typings (opens new window)也是一个用来管理 Typescript 定义的库。这种方式已经不推荐使用。

  • 安装typings工具
# Install Typings CLI utility.
npm install typings --global
# 或
yarn global add typings
1
2
3
4
  • 通过工具安装定义库
# 安装jquery定义库
typings install jquery --save
1
2

安装之后,在你的项目文件夹中会自动创建一个名为 typings 的文件夹来专门保存类型定义的库。 如果这个定义来自 DefinitelyTyped, 则现有加上一个参数 --ambient typings install jquery --ambient --save

  • 配置 它自己需要一个配置文件 typings.json,可以用它来管理项目使用到的类型定义,这样,类似于 NPM,我们可以使用 install 命令来自动安装需要的类型定义。typings.json配置如下:
{
  "ambientDependencies": {
    "jquery": "registry:dt/jquery#1.10.0+20161119044246"
  },
  "dependencies": {
   "jquery": "registry:dt/jquery#1.10.0+20161119044246"
  }
}
1
2
3
4
5
6
7
8

以后,直接使用typings install就可以安装定义在配置文件中的所有的包了。

# 2.3 @Types

DefinitelyTyped和# Typings都需要使用另外一套系统来管理类型定义显然不太方便。在 Typescript 2.0 之后,TypeScript 将会默认的查看 ./node_modules/@types 文件夹,自动从这里来获取模块的类型定义,当然了,你需要独立安装这个类型定义。Microsoft 在 The Future of Declaration Files (opens new window)介绍了 TypeScript 的这个新特性。

默认情况下,所有的 @types 包都会在编译时应用,任意层的 node_modules/@types 都会被使用,进一步说,在 ./node_modules/@types/ , ../node_modules/@types/, ../../node_modules/@types/ 都被应用。如果你的类型定义不在这个文件夹中,可以使用 typesRoot 来配置,只有在 typeRoots 中的包才会被包含,配置如下:

{
   "compilerOptions": {
       "typeRoots" : ["./typings"]
   }
}
1
2
3
4
5

现在,只有在 ./typings 中的才会应用,而 ./node_modules/@types 中的则不会。 如果配置了 types,则只有列出的包才会包含。

{
   "compilerOptions": {
       "types" : ["node", "lodash", "express"]
   }
}
1
2
3
4
5

这样将只会包含 ./node_modules/@types/node, ./node_modules/@types/lodash 和 ./node_modules/@types/express,其它的则不会被包含进来。如果配置为"types": []则不会包含任何包。

# 2.4 *.d.ts和@types关系

@types是npm的一个分支,用来存放*.d.ts文件,如果对应的npm包存放在@types中,要使用必须下载!如果是自己本地的*.d.ts申明文件,则和@types没有任何关系!

# 2.5 declare 和 export

.d.ts 文件中的顶级声明必须以 "declare" 或 "export" 修饰符开头。

通过 declare 声明的类型或者变量或者模块,在 include 包含的文件范围内,都可以直接引用而不用去import或者import type相应的变量或者类型。

也就是说,declare 告诉 TS 编译器,你担保这些变量和模块的存在,并声明了响应的类型,编译的时候不需要提示错误。

  1. .d.ts文件顶级声明 declare 最好不要跟 export 同级使用,不然在其他 ts 引用这个 .d.ts 的内容的时候,就必须手动 import 导入了。
  2. 在.d.ts文件里如果顶级声明不用 export 的话,declare和直接写 type、interface 效果是一样的,在其他地方都可以直接引用。

# 三、 编写语法

从类型type角度分为:基本类型(string、number、boolean、undefined、symbol)其混合 下面我们介绍下 “.d.ts” 的几种声明的写法

# 3.1 全局类型

  • 变量
  • 函数
  • 用interface 声明函数
  • class
  • 对象
  • 混合类型
  • 模块化的全局变量

# 3.2 模块化的全局变量

定义全局变量的时候需要引入(别人写的)文件

import { PluginFunc } from 'dayjs'

declare const plugin: PluginFunc
export as namespace plugin; // 可选的全局用法,在UMD上下文中,可在全局作用域下访问 plugin
export = plugin
1
2
3
4
5

# 3.3 模块化(CommonJS)

通过require的方式引入模块化的代码

// d.ts
declare module "ever" {
    export let a: number
    export function b(): number
    export namespace c{
        let c: string
    }
 }
 // 引用
 cosnt ever = require('ever)
 ever.a = 100
 ever.b = function() {
     return 100 + 300
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.4 ES6的模块化方式(import export)

方法和 ES6 的模块化一样。

export declare let a1: 1
export declare let a2: 2
// 或
declare let a1: 1
declare let a2: 2
export { a1,a2 }
1
2
3
4
5
6

# 3.5 UMD

有一种代码,既可以通过全局变量访问到,也可以通过require的方式访问到。

declare namespace ${
    let a:number
    export type b=string // 通过export关键字暴露的成员,可以在其它同名的 namespace/class/function 中访问
}
 
declare module "$" {
    export = $
}
1
2
3
4
5
6
7
8

# 3.6 其他

有时候我们扩展了一些内置对象。给Date的内置对象扩展方法

interface Date {
    format(f: string): string
}
1
2
3

# 四、.d.ts声明文件模板

# 4.1 查看库结构

一个库往往由许多个模块组成,清晰的目录结构十分重要。例如,当我们的库包含如下模块时:

myLib

​ +---- index.js

​ +---- foo.js

​ +---- bar

​ +---- index.js

​ +---- baz.js

使用该库时,就有不同的导入:

var a = require("myLib");
var b = require("myLib/foo");
var c = require("myLib/bar");
var d = require("myLib/bar/baz");
1
2
3
4

则相应的,我们的声明文件应该在如下的目录结构中:

@types/myLib

+---- index.d.ts

+---- foo.d.ts

+---- bar

+---- index.d.ts

+---- baz.d.ts

# 4.2 类型文件测试

  • 如果我们希望自己的库提交到DefinitelyTyped供所有人使用,则需要做如下操作:(当然,这种是2.0之前的常见做法,现在之间用@types就好了)

    1. 在node_modules/@types/[libname]处创建新的文件夹;
    2. 在该文件夹下创建一个index.d.ts文件,并将上面的参考示例复制进去;
    3. 根据我们对模块使用中断的地方,来把index.d.ts填充完整;
    4. 当index.d.ts文件填充至满意时,下载DefinitelyTyped/DefinitelyTyped (opens new window)并按README的指导来操作。
  • 其它情况,例如只需要在自己的项目中使用,则只需做一些简单操作:

    1. 在项目根目录下创建一个[libname].d.ts文件;

    2. 在该文件中添加declare module "[libname]" { };

    3. 将参考示例复制到"{ }"中,并根据模块中断的地方进行填充至满意

      declare module "myLib" {
          export let a: number
          export function b(): number
          export namespace c{
              let c: string
          }
       }
      
      1
      2
      3
      4
      5
      6
      7

# 4.3 拓展插件声明模板

当我们想要拓展库的功能时,可以通过插件声明模板的写法来添加。

该写法下,文件需要包含至少一个顶级的 import 或 export,即使它只是 export {}。

以 vue3 官方为例,让 ts 支持 .vue 文件的导入支持。(ts只支持模块的导入导出, 但是有些时候你可能需要引入css/html等文件, 这时候就需要用通配符让ts把他们当做模块)

declare module '*.vue' {
  import { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

// 可以识别vue文件
import X1 from './X1.vue';
export default defineComponent({
	components:{X1}
})
1
2
3
4
5
6
7
8
9
10
11

又比如全局组件的类型声明:

// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
declare module 'vue' {
  export interface GlobalComponents {
    TmActionMenu: typeof import('./components/tm-action-menu/tm-action-menu.vue')['default']
  }
}

export { }
1
2
3
4
5
6
7
8
9
10

# 4.4 拓展全局模板

注意:声明模版是用于为库进行声明的,而不是起实际作用的库,真正起作用的是全局修改模块,而不是声明文件本身。

// Type definitions for [~库的名字~] [~版本号,可选~]
// Project: [~工程名~]
// Definitions by: [~汝名~] <[~主页链接~]>
/*~ 这是个全局修改模块的模板,本文件应该被重命名为 index.d.ts
 *~ 并置于与模块同名的文件夹下,
 *~ 例如,模块名为 "super-greeter", 
 *~ 则本文件路径为 'super-greeter/index.d.ts'
 */
/*~ 注意,如果你的全局修改模块可以直接调用或者用作构造函数,
 *~ 则应在此结合模块函数或者模块类的模板文件。
 */
declare global {
  /*~ 此处声明的成员将被置于全局global命名空间中,
   *~ 或用于增强该命名空间中已有的成员。
   */
  interface String {
    fancyFormat(opts: StringFormatOptions): string;
  }
}
/*~ 如果你的模块需要导出值或者类型,照常写就ok */
export interface StringFormatOptions {
  fancinessLevel: number;
}
/*~ 例如声明一个方法 */
export function doSomething(): void;
/*~ 如果你的模块啥也不导出,则写下面这句话,否则,删掉这句话 */
export {};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 五、案例

/** 作为函数使用 */
declare function People(w: number): number
declare function People(w: string): number

declare class People {
    /** 构造函数 */
    constructor(name: string, age: number)
    constructor(id: number)

    // 实例属性和实例方法
    name: string
    age: number
    getName(): string
    getAge(): number

    /** 作为对象,调用对象上的方法或者变量 */
    static staticA(): number
    static aaa: string
}

/** 作为对象,调用对象上的方法或者变量 */
declare namespace People {
    export var abc: number
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
编辑 (opens new window)
上次更新: 2023/8/22 19:22:36
declare声明
命名空间namespace

← declare声明 命名空间namespace→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式