likes
comments
collection
share

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

作者站长头像
站长
· 阅读数 23

在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declare(声明)的意思。类型声明文件大致可分为以下介绍的三类:

内置类型声明

在 ts文件里我们使用 document 等对象会有类型提示:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

是因为 ts 提供了一些内置的类型声明:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

看该文件的路径可以知道它是存储在 VS Code 里的,如果使用的是其它编译器,只要全局安装过了 ts,编译器就会去搜寻内置的 .d.ts 文件。

可以看到,在 .d.ts 文件中,顶级声明都以 declare 作为开头,这样其它地方使用时就无需额外引入了。但是如果在顶级声明中还使用了 export,比如:

export declare interface ILoginReq extends IClientSetting {
  scope?: string
}

或者直接省略 declare

export interface ILoginReq extends IClientSetting {
  scope?: string
}

那么在其它地方使用类型 ILoginReq 时就需要先引入。

指定内置声明文件

这些内置的 .d.ts 在 ts 的 GitHub 仓库中可以查看:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

有时候我们编写的一些代码,比如使用 promise.finally 时会遇到报错:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

就可以通过修改 tsconfig.json 文件的 compilerOptions.lib 配置,lib 的可选值可查看官方文档

{
  "compilerOptions": {
    "lib": ["ES2015", "ES2016", "DOM", "ES2018"]
  }
}

"ES2018" 意味着使用 es2018.d.ts,其 中引用了 es2018.promise.d.ts:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

在 es2018.promise.d.ts 中就定义了 Promisefinally 属性:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

其实也可以直接更改 compilerOptions.target"ES2018"compilerOptions.lib 会根据 target 自动配置。顺便一提,我们无需担心浏览器是否能识别运行 ES2018 的语法,因为项目中最终 ts 一般是通过 babel 转换的。

外部定义的类型声明

有些第三方库,如 axios,安装后其本身就有类型声明文件 index.d.ts:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

而另一些,如 lodash,在使用 npm 安装后则没有 .d.ts 文件,直接引入会报错:

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。提示里已经告诉了我们解决办法:

npm i --save-dev @types/lodash

之后就能在 ts 文件中正常使用 lodash 了。而这个安装包,来自于 DefinitelyTyped,是一个公共的存放类型声明的库。

自己定义类型声明

如果找不到现成的类型声明文件,就需要我们自己定义了。比如,我们可以自己在项目中新建个 lodash 的类型声明文件 index.d.ts,ts 编译器会扫描并加载项目中所有的 ts 声明文件(如果执行报错就把 index.d.ts 放到 node_modules\lodash 中):

declare module 'lodash' {
  export function cloneDeep(any): any
}

declare module 用于声明模块,其后在 {} 中使用 export 导出了模块内的 cloneDeep 函数 function cloneDeep(any): any。这样就能在 ts 文件中使用 lodash 的 cloneDeep 方法了:

import _ from 'lodash'
const obj = {
  name: 'Jay'
}
const newObj = _.cloneDeep(obj)

上面是声明了模块,还可以声明变量、函数、类和文件:

declare let bianlian: string
declare function fn(): void
declare class Lei {
  constructor(public name: string)
}
declare module '*.jpg'
declare module '*.mjs'

但是,如果声明的是 interface 等只存在于 ts 的类型系统中的,通常不需要在 interface 前加上 declare 关键字,ts 编译器会自动识别并合并相同名称的 interface 声明。

declare 也可以直接在 ts 文件中使用,比如我们想使用 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $jQuery 了。但是在 ts 中,编译器并不知道 $jQuery 是什么东西。我们可以使用 declare 来定义它的类型:

declare var jQuery: (selector: string) => any
jQuery('#foo')

declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

jQuery('#foo')

TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar TS 中的类型声明文件在 ts 项目中,我们能看到一些 .d.ts文件,它们是类型声明文件,d 可以看成是 declar

转载自:https://juejin.cn/post/7368035468611977231
评论
请登录