前言

在把项目改造支持 Typescript 之后, 跑了几个迭代,也踩了一些坑。还好这些坑总体可控, 没翻车, 所以就写篇文章分享一下, 如果想要体验 vue+typescript 的同学可以看看。
之前配置的过程查找了很多资料,但大部分都是下面两种方案:

  • 基于 vue-cli3+的全新的项目
  • vue-cli2 的老项目引进 typescript

但是我们公司的项目在新建项目的时候并没有引入 typescript 的支持。如果后期想引入 typescript 呢,有没有一种向后兼容(backward compatibility)的方式整合到现有的项目中呢,既可支持 ts,也可以兼容 js,这样现有的代码就几乎不用改动了。
下面分三部分来描述 👇:

  • 一个基于 vue-cli3+、支持 typescript 的新项目是怎么配置的?
  • 如何应用这些不同的配置到现存的项目中?
  • 因为子项目需要引入主模块的 app,还有 vue,element-ui 等等是以 extenal 引进来的,这些需要如何配置才不使 ts 报错?

1. 一个基于 vue-cli3+、支持 typescript 的新项目是怎么配置的?

  • Typescript 是 JavaScript 的超集

正如官方说描述: "A superset of Javascript", Typescript 更接近面对对象语言, 支持更多的 JS 不能支持的语法:
例如,链式语法, js: res && res.data && res.data.name ; ts 的话: res?.data?.name  虽然 babel 也有类似的插件实现该语法 。
而且 ts 是向后兼容的, 也就 js 的语法都可以直接在 ts 都可以运用。

  • 更严谨,能提前避免一些 bug 出现, 同时有利后期项目的维护

js 是解析式弱类型语言。比如,js 很多情况存在隐形转换,但是又是在运行时才报错, 这无疑给我们埋了很多未知的坑,特别是在一些大型项目中,所以一些大型项目都投入 ts 的怀抱,例如ant-designvscode、 还有即将发布的 vue3 版本vue-next。 ts 是要编译成 js 才能在浏览器中执行的, 所以在编译过程中可以提示我们很多可能出现错误的地方, 我们以此纠正。

  • 更好的开发体验

这个主要是编辑器更智能,更友好的提示。 我们现在的编辑器提示功能主要是借助一些 Snippets 插件实现的, 但是 ts 的 xx.d.ts 的声明文章对编辑器来说更智能,更友好。可以说申明文件写的越完整,编辑器越智能,例如

declare module "app" {
  import { Store, Module } from "vuex";
  import { IState } from "@/store";
  type SubModuleOptions = {
    name: string;
    store?: Module<IState, any>; //TODO:Module<S, R> 中的R指的是rootState, 应该app主项目还没改造成typescript, 先用any
    generator: (path: string) => () => Promise<Vue>;
  };
  interface System {
    registerModule(subModuleOptions: SubModuleOptions): void;
  }
  let system: System;
  let utils: Record<string, any>;
  let config: Record<string, string>;
  let request: Record<string, any>;
  let router: Record<string, any>;
  let store: Store<IState>;
}

更多关于 ts 的知识,请查看官方文档https://www.typescriptlang.org/,网上也有很多文章描述采用 ts 的优点,缺点。 这里就不再展开了,下面开始我们的正式内容。ヾ(≧▽≦*)o

新建一个空的 vue+typescript 的项目

新建一个基于 vue-cli3+的 typescript 项目, 网上有很多这种文档, 比如https://segmentfault.com/a/1190000019905650, 注意选择 Use class-style component syntax?  的时候我们选择 yes, 因为我们需要用类组件。
对比与不支持 typescript 的 vue 项目, 新的地方如下:

├─src
│  ├─main.ts
│  ├─shims-tsx.d.ts
│  └─shims-vue.d.ts
├─tsconfig.json

从名字可以看出这几个文件的作用, 但是这里我们先不用理会。 此外当然 package.json 和.eslintrc.js 中的配置也有些差别, 对比发现,其他 package.json 只是多了vue-class-component、vue-property-decorator、typescript、@typescript-eslint/parser 、@typescript-eslint/parser、@vue/cli-plugin-typescript、@vue/eslint-config-typescript   这几个包。

2. 应用这些不同点到现存的项目中

我们要怎样应用这些不同点到现有的项目中呢, 摸着石头过河,我们在同样的目录结构下直接复制这些不同的新文件过来, 然后增加 package.json 不存在的包, 修改 main.js 为 main.ts(这里可能有坑), 复制.eslintrc.js 配置过来。
准备好这些之后, 删除 node_modules 重新 npm install  安装一次

3. 因地制宜,根据项目具体情况配置

直接运行项目的话,可能会报很多类似的?Cannot find module 'xxx' or its corresponding type declarations. 的错误, 这是因为找不到对应报的声明文件。 根据项目的具体情况,例如我们的项目 vue、vuex、element-ui、app 等是通过 externals 方式引入的, 所以在 package.json 中找不到对应的依赖, 这样的话也没有这些包声明文件。还好 vue、vuex、element-ui 是提供声明文件的, 我们只需要把这些包安装成开发依赖 devDependencies ,在后面的开发中我们就可以使用这些声明文件了。 但是 app 是主项目的 umd 包,也是没有申明文件的, 这时候我们就要针对 app 自己写声明文件了。 最简单的就是在 src 目录下新建一个 typings 目录,在创建一个 app.d.ts, declare module "app"  声明就可以了, 这样就不会报错了。 更多申明文件怎么写可以参考https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html 。 此外可能还有出现其他的错误, 比如 eslint 错误, 这些要根据具体错误具体解决了。

4.利用 ts 进行业务开发

搭建好 ts 的开发环境之后, 因为 ts 是向后兼容的,所以之前的业务代码全部不用改。后面用 ts 开发的话, 学会使用 ts、vue-property-decoratorvue-class-component就行了。 后面有机会可以写 tsconfig 的配置, 声明文件, vuex 这些内容了,感谢大家的阅读了, 有问题欢迎沟通哈。

03-05 16:29