TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。

  1. 在 tsconfig include 字段包含的范围内编写 .d.ts,都将被自动识别。
  2. 在x.js相同目录创建同名声明文件x.d.ts,这样也会被自动识别;
  3. node_modules/@types/下存放各个第三方模块的声明文件,通过yarn add @types/react自动下载到此处,自己编写的声明文件不要放在这里;
  4. 作为 npm 模块发布时,声明文件可捆绑发布,需在package.json中指明”types”: “./types/index.d.ts”

    隐式any类型

    在tsconfig.json中默认开启”noImplicitAny”: false;如果把该属性关闭,可以直接在 TypeScript 中引用 JavaScript(无声明文件)的库,所有的引入都会被默认为any类型,也不会提示类型错误
    为了规范编码,总是打开”noImplicitAny”: true,typescript的作用就是为了类型检查,这样当发生上述情况时,编译器会阻止编译,提示我们去加上类型规范。

    ts中导出js文件

    ```typescript // hello.js export const hello = () => console.log(‘hello’)

// index.ts import {hello} from ‘./hello’ // 如果使用 vscode,编辑器就会给出错误提示: // [ts] 无法找到模块“./hello”的声明文件。“src/hello.js”隐式拥有 “any” 类型。 hello()

// 如果执行编译,控制台也会给出同样的错误提示: // Could not find a declaration file for module ‘./hello’. ‘src/hello.js’ implicitly has an ‘any’ type.

  1. ts中直接引入js文件,需要先编写声明文件。为hello.js添加声明文件:
  2. ```typescript
  3. // hello.d.ts
  4. export declare const hello:() => void

当文件结构比较复杂,可以用namespace来定义

  1. // hello.d.ts
  2. export as namespace hello;
  3. export = hello;
  4. declare namespace hello {
  5. export const hello: () => void;
  6. }

TS中导入.png/.json等文件时

不止是在 TypeScript 中导入未声明 JavaScript,导入.png、.json等文件时也同样需要去编写声明文件
创建一个声明文件src/shims.d.ts

  1. // shims.d.ts
  2. declare module '*.png' {
  3. const value: string
  4. export = value
  5. }
  6. // index.ts
  7. // 之后在 TS 中导入不会报错
  8. import avatar from './avatar.png'

也可使用require,不过require会提示错误

  1. const avatar = require('./img/avatar.png')
  2. // 可能会提示 require 未定义,有两种方式:
  3. // 1. 自行声明:declare const require: any
  4. // 2. yarn add -D @types/node

使用第三方模块,没有声明文件

使用第三方不是 TypeScript 编写的模块时,我们可以直接下载对应的声明文件:yarn add @types/{模块名}
有些模块是没有对应的声明文件的,需要我们自己编写声明文件,以rc-form为例,需在src/shims.d.ts中添加对应代码:

  1. // shims.d.ts
  2. // 新增部分
  3. declare module "rc-form" {
  4. // 在此只是简单地进行类型描述
  5. export const createForm: any;
  6. export const createFormField: any;
  7. export const formShape: any;
  8. }

webpack设置别名[alias]时报错

当 webpack 中配置了别名,在 TS 中使用时会出现找不到模块

  1. // webpack.config.js
  2. const config = {
  3. // ...
  4. aliases: {
  5. // 公共的工具类、容器和组件
  6. utils: path.resolve('../utils'),
  7. },
  8. // ...
  9. }
  10. // index.ts
  11. import {ua} from 'utils/broswer'
  12. // Cannot find module 'utils/browser'

需在 tsconfig.json 添加baseUrl和paths的配置:

  1. // tsconfig.json
  2. {
  3. "compilerOptions": {
  4. // ...
  5. "noImplicitAny": true,
  6. // 添加配置
  7. "baseUrl": ".",
  8. "paths": {
  9. "utils/*": ["../utils/*"],
  10. "components/*": ["../components/*"]
  11. }
  12. },
  13. "include": ["./src/*", "./src/**/*"],
  14. "exclude": ["node_modules"]
  15. }

类型window不存在属性X

通过 script、src 引入的对象在 window.X 是可以直接访问的,但在 TS 中直接使用时会提示不存在相应属性(The property ‘X’ does not exist on value of type ‘window’),需要对 window 进行扩展,直接在src/shims.d.ts中扩展

  1. // shims.d.ts
  2. interface Window {
  3. X: any
  4. }
  5. // index.ts
  6. console.log(window.X) // success

想复用一些类型,从其他文件导入了一些内容,这时报错

  1. // shims.d.ts
  2. import {IPerson} from './interfaces/index.ts'
  3. interface Window {
  4. X: any
  5. }
  6. // index.ts
  7. console.log(window.X) // fail: 类型“Window”上不存在属性“X”

套一层global能解决报错

  1. // shims.d.ts
  2. import {IPerson} from './interfaces/index.ts'
  3. // global 包裹
  4. declare global {
  5. interface Window {
  6. X: any
  7. }
  8. }
  9. // index.ts
  10. console.log(window.X) // success

但没有import语句时,使用declare global会提示错误