如何开发一个基于 TypeScript 的工具库并自动生成文档

为何用 TypeScript?

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source. ———— TypeScript 官网

1.第一时间发现类型错误

rollbar 统计,在前端项目中 10 大错误类型以下图所示:html

JavaScript 错误类型

其中有 7 个是类型错误(TypeError):前端

  • Cannot read property 'xxx' on undefined:没法在 undefined 上读取 xxx 属性,一般出如今 a.b.c 的状况。
  • 'undefined' is not an objectundefined 不是对象
  • null is not an object:null 不是对象
  • 'undefined' is not a functionundefined 不是函数,一般出如今 a.b.c() 的状况。
  • Object doesn't support property
  • Cannot read property 'length':没法读取 'length' 属性,原本指望一个数组,可是变量的实际类型却不是数组。
  • Cannot set property of undefined:没法给 undefined 设置属性。

除了 7 个 TypeError,还有一个 ReferenceError:vue

  • 'xxx' is not defined:xxx 没有定义。

还有一个 RangeError:java

  • 在 JS 中,数组越界并不会抛出 RangeError,可是某些函数则抛出这个错误

range error

嘿嘿,看着这些错误眼不眼熟?webpack

因为 JavaScript 是一门很灵活的语言,因此以上这些错误每每要在代码运行时才能发现。git

2.智能提示

在使用 JavaScript 时,编辑器的智能提示每每颇有限,好比提示你最近输入的变量。github

可是基于 TypeScript,因为知道当前变量是什么类型,因此编辑器能通过类型推导后为你提示这个变量的全部属性,以及对于函数的参数进行提示和校验。web

智能提示

此外,对于通常的 JavaScript 项目也能够本身编写 .d.ts 声明文件,来获取类型推导能力。

至于其余的优势在这里就不展开了...typescript

综上,在项目中使用 TypeScript 能让你极大地提升工做效率,并减小大量的类型错误。json

TypeScript 初体验

因为目前业务项目中的框架用的是 Vue.js,众所周知 2.x 版本对于 TypeScript 支持的不是很好,因此就打算先搞个工具函数库项目试试水。

语言学习

略,这个各类资料不少,这里就不赘述了...

项目架构

  • 项目入口:src/index.ts,没有实质内容全是 export * from '...'(都是纯函数)
  • 实际代码:根据工具函数分类放在不一样的文件中,例如

    • string(字符串相关)
    • env(环境探测)
    • url(连接地址)
    • ...
  • 单元测试:test/
  • 文档目录:docs/
注意: package.json 中的 sideEffects 字段要写成 false,这样能够方便业务代码打包时 tree-shaking

相关工具链

以前对于 TypeScript 一直在观望的缘由之一就是相关工具链的搭配还不是很成熟。不过如今却是基本明晰了:

  • 1.代码转译 babel([[译] TypeScript 和 Babel:美丽的结合][4])

TypeScript 和 babel 均可以将你的 ES6+ 代码转成 ES5。

但在 Babel v7 以前将两个独立的编译器(TypeScript 和 Babel)连接在一块儿并不是易事。编译流程变为:TS > TS Compiler > JS > Babel > JS (again)

如今只要安装 @babel/preset-typescript 这个包就能让你完美结合 babel 和 TypeScript。

不再用纠结到底用 tslint 仍是 eslint 了,TypeScript 官方已经钦定了 eslint(Migrate the repo to ESLint #30553)。

  • 3.单元测试 jest([[RFC] Migrate Jest to TypeScript #7554][7])

嘿嘿,Facebook 的 jest 和 yarn(Yarn's Future - v2 and beyond #6953) 都抛弃自家的 Flow 转投 TypeScript 的怀抱了

虽然 rollup 本身用的是 rollup-plugin-typescript,不过项目中仍是选了 rollup-plugin-typescript2

改造过程

  • 安装各类依赖
  • 配好各类配置文件(eslint、babel、commitlint、jest),其中最重要的是 tsconfig.json
  • 源代码的文件名后缀由 .js 改为 .ts(单测的文件也改)
  • 而后 TypeScript 的静态代码类型检查就会告诉你有什么错误
  • 看状况改代码,或者是加 ignore 注释(有时甚至须要改 tsconfig 的配置)

文档

文档标准

TypeScript 官方有一套基于 jsdoc 的文档标准 tsdoc

export class Statistics {
  /**
   * Returns the average of two numbers.
   *
   * @remarks
   * This method is part of the {@link core-library#Statistics | Statistics subsystem}.
   *
   * @param x - The first input number
   * @param y - The second input number
   * @returns The arithmetic mean of `x` and `y`
   *
   * @beta
   */
  public static getAverage(x: number, y: number): number {
    return (x + y) / 2.0;
  }
}

生成文档

因而顺藤摸瓜找到 typedoc 这个自动文档网站生成器。但这玩意儿的常规操做就是读取源代码,而后 duang 地一下,生成一堆页面。

虽然这样解决了文档生成,可是无法进行开发时实时预览文档。

自动生成

0.失败尝试:结合 vuepress

因为 typedoc 能导出 md 文件,因此尝试过将其结合 vuepress。不过因为 typedoc 在生成时会先清空目标目录下全部文件,折腾起来太麻烦(好比作个插件)。

1.下策:手动触发文档生成

没啥好说的,适用于有毅力的同窗。

2.中策:监听源文件变化,自动触发文档生成

虽然能自动生成文档页面了,不过预览时无法自动刷新页面。

3.上策:借助 webpack、gulp、grunt 自动生成文档并刷新页面(正好有这三者的 typedoc 插件

说到开发时自动刷新页面,第一个天然想到 browser-sync

  • 虽然说 webpack 无所不能,不过杀鸡焉用牛刀
  • grunt 这玩意儿有点儿落伍了
  • gulp 正好之前捣鼓过,加这个小需求正好

最后这里贴一下 gulpfile.js 的代码,节省一下也有相关需求同窗的时间吧。

const gulp = require('gulp')
const typedoc = require('gulp-typedoc')
const browserSync = require('browser-sync').create()

const runTypeDoc = () => gulp
    .src(['src'])
    .pipe(typedoc({
        out: './docs',
        // 这个文件里都是 export * from '...' 就不必导出文档了
        exclude: 'src/index.ts',
        tsconfig: 'tsconfig.json',
    }))

const reload = (done) => {
    browserSync.reload()
    done()
}

const runBrowserSync = (done) => {
    browserSync.init({
        server: {
            baseDir: './docs',
        },
    })
    done()
}

const watch = () => gulp.watch(
    ['README.md', 'src/*.ts'],
    gulp.series(runTypeDoc, reload)
)

gulp.task('default', gulp.series(runTypeDoc, runBrowserSync, watch))

以上 to be continued...

参考资料

相关文章
相关标签/搜索