构建 Typescript 知识体系(十二)-如何编写TS类库

1,294 阅读2分钟

这是我参与更文挑战的第十八天,活动详情查看:更文挑战

这里我们学习如何在 TS 中使用外部类库,以及如何为他们编写声明文件

类库一般分为三类

  • 全局类库
  • 模块类库
  • UMD 类库

如:jquery 是一种 UMD 库,即可以通过全局的方式引用,也可以通过模块化的方式引用,jQuery 因为使用 JavaScript 编写的,因此在 TS 中引用时会提示没有声明文件,但大多数类库的类型声明文件都可以在这里找到进行安装,如果没有则需要自己写了 🤷‍♀️

一. 编写全局类库的声明文件

image.png

1.1 类库的源码- global-lib.js

// 一个用js编写的全局类库
function globalLib(options) {
  console.log(options);
}

globalLib.version = "1.0.0";

globalLib.doSomething = function () {
  console.log("global doSomething");
};

1.2 类库的 TS 声明文件-global-lib.d.ts

/* 
declare 为外部变量提供声明

函数和命名空间的声明合并,相当于为函数添加了一些属性
*/

declare function globalLib(options: globalLib.Options): void;

declare namespace globalLib {
  const version: string;
  function doSomething(): void;
  interface Options {
    [key: string]: any;
  }
}

1.3 类库的使用-index.ts

$(".root").css("color", "red");

globalLib({ x: 1 });

globalLib.doSomething();

1.4 在 html 中引用类库

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="root" class="root">hello</div>
    <script src="/src/libs/global-lib.js"></script>
  </body>
</html>

二. 编写模块类库的声明文件

image.png

2.1 类库的源码-module-lib.js

const version = "1.0.1";

function doSomething() {
  console.log("moduleLib do something");
}

function moduleLib(options) {
  console.log(options);
}

moduleLib.version = version;
moduleLib.doSomething = doSomething;

module.exports = moduleLib;

2.2 类库的 TS 声明文件-module-lib.d.ts

declare function moduleLib(options: Options): void;

interface Options {
  [key: string]: any;
}

declare namespace moduleLib {
  const version: string;
  function doSomething(): void;
}

export = moduleLib;

2.3 类库的使用-index.ts

import moduleLib from "./module-lib";

moduleLib.doSomething();

三. 编写 UMD 类库的声明文件

image.png

3.1 类库的源码-umd-lib.js

(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    define(factory);
  } else if (typeof module === "object" && module.exports) {
    module.exports = factory();
  } else {
    root.umdLib = factory();
  }
})(this, function () {
  return {
    version: "1.0.1",
    doSomething() {
      console.log("umdLib do Something");
    },
  };
});

3.2 类库的 TS 声明文件-umd-lib.d.ts

declare namespace umdLib {
  const version: string;
  function doSomething(): void;
}
// 专为UMD库 写的语句
export as namespace umdLib;

export = umdLib;

3.3 类库的使用-index.ts

import umdLib from "./umd-lib";

umdLib.doSomething();

3.4 UMD 库也可以通过全局的方式引用

3.4.1 修改 tsconfig.json 配置


"allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */

3.4.2 在 html 中引用类库

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="root" class="root">hello</div>
    <script src="/src/libs/umd-lib.js"></script>
  </body>
</html>

3.4.3 在 html 中引用类库

// import umdLib from './umd-lib'

umdLib.doSomething();

四. 插件

  • 模块插件
  • 全局插件

有时候需要给类库添加一些自定义的方法,比如想给 moment 类库添加一些自定义的方法

模块化插件---declare module

import moment from "moment";

declare module "moment" {
  export function myFunc(): void;
}

moment.myFunc = () => {};

全局化插件

在上文 编写全局类库的声明文件的基础上拓展一个函数

index.ts 文件

declare global {
  namespace globalLib {
    function doAnyThing(): void;
  }
}

globalLib.doAnyThing = () => {};

这样对全局命名空间造成了一定污染,一般不建议这样做

五. 声明文件的依赖

如果一个类库比较大的话,它的声明文件会很长,一般会按照模块划分, 这些声明文件就会存在一定的依赖关系