Vue2.x项目添加typescript 采坑

3,048 阅读5分钟

项目背景: vue-cli3生成的vue2.x的项目,ide是vscode

1、安装

vue add typescript

? Use class-style component syntax? (Y/n) y
? Use Babel alongside TypeScript for auto-detected polyfills? (Y/n) y

这两项都选择Yes,第一个是因为要使用官方维护的vue-class-component 装饰器来改造项目,第二个babel转义也是需要的。

2、重新看项目

1、之前项目下的.js文件全部变成.ts文件。
2、新增了HelloWolrd.vue,Home.vue ,App.vue文件,可以用来参考vue-class-component写法
3、新增了shims-tsx.d.ts和shims-vue.d.ts 这2个声明文件(**重要,由于没用到jsx语法,因此只关心第二个)
4、新增了tsconfig.json  (**重要,ts的配置文件)

3、模块相关问题

1 、之前的引用方式因为偷懒都去掉了文件后缀名,这里需要加上; import xx from xx.vue
2import 时路径别名的引用需要在tsconfig.json中添加,如果别名指向了具体文件,这里也需要具体到文件
    "paths": {
      "@/*": [
        "src/*"
      ],
      "@components/*": [
        "xxx/xxx/components/*"
      ]
  }
3import 如果别名指向的是具体的js文件,会报错,没有找到模块xxx的声明文件。
    Could not find a declaration file for module '@xxx/vendor'
    这时需要修改shims-vue.d.ts声明文件,即可
    declare module '@xxx/vender'
    (这里说明下,在项目中单独在一个路径维护一个vendor.js文件包括vue,vuex,vie-router等官方库,所有业务统统引用这个vendor,如有版本库更新,只修改这个vendor.js即可)

4、ts相关错误

1、定义对象时记得要声明如, const myObj: {[index: string]:any} = {}
    不然在通过myObj[xxx]方式访问属性是报错ts7053
2window.xxx 报错
    用另一个any变量缓存,let win:any = window
    在使用(<any>window).xxx访问
3MyObj.__defineGetter__('xx',function(){})   报错ts2339
    需要使用defineProperty来改造
    Object.defineProperty(MyObj,'xx', { get: function(){} } )
    **注意  如果是在给构造器添加getter的话,要在其原型链上添加,如下
    Object.defineProperty(Number.prototype,'xx',{get: function(){} })

5、vue组件写法

1、store 中的state 需要初始化,不然会报错
2、在vue的原型链上添加或者vue.use(xxx)添加插件时,需要

模块补充,如:

import Vue from "vue"    
//在vue组件内疚可以使用this.xxx来访问了
declare module "vue/types/vue" {
  interface Vue {
    xxx: xxx
  }
}
3、tsconfig.json中的typeRoots 配置, 直接指向一个目录,目录下定义全局interface等,使用时不需要import 可以直接用
4、这里有个Keng 。我在x.d.ts中添加了import语句,导致这个d.ts无法被识别,使用时需要import这个d.ts (如何写好一个d.ts文件?)
5、vue-router 导航钩子,需要注册才能使用。(在定义钩子方法时,不能随意添加,只能在router.js中定义的导航组件中添加钩子方法)
Component.registerHooks([
  "beforeRouteEnter", //进入路由之前
  "beforeRouteLeave", //离开路由之前
  "beforeRouteUpdate"
]);
6this.$refs.xxx.show()
先使用vue-property-decorator 中的Ref修饰器
@Ref() readonly xxx:yyy (xxx是变量名,yyy是引入的.vue文件)
在使用this.xxx.show时会报错:ts2339 property 'show' does not exist on type vue
解决方案:https://stackoverflow.com/questions/57416991/vue-typescript-how-to-avoid-ts-error-when-accessing-child-components-methods
原因:https://github.com/kaorun343/vue-property-decorator/issues/257  .vue文件export的是一个vue 实例,不是我们extends之后的,因此没有我们自定义的property
7、document.getElementById('xxx').style 报错 ts2339 Property 'style' does not exist on type 'Element'
这里因为getElementById/querySelector等方法返回的是Element,Element在W3C中不包含这个,HTMLElement,SVGElement等继承Element 这里在实际使用时,根据实际情况强制类型为HTMLElement。如:`<HTMLDivElement>document.getElementById('xxx')`

6,在原不支持ts的webpack.config.js中对ts的支持

1),RegeneratorRuntime is not defined

npm install --save-dev @babel/plugin-transform-runtime

"plugins": ["@babel/plugin-transform-runtime"] 版本都要7以上

2),TypeError: this.setDynamic is not a function

"devDependencies": {
    "@babel/plugin-transform-runtime": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
}
都要版本7以上, this.setDynamic 是因为 transform-runtime 是6.x

3),Unexpected token: name «win», expected: punc «;»

是因为uglify-js报错 ,用 terser-webpack-plugin 替换

4),cant not resolve ./poster

import poster from "./poster"  (.ts文件)

需要在extension 添加['.ts']

5),Error: Cannot find module '@babel/plugin-runtime'

@babel/runtime isn't a plugin. It's a time package which you should put in your dependencies when using @babel/transform-runime

不是一个plugin ,不能用在pluginconfig中

6),Cannot assign to read only property ‘exports’ of object

import 和 module.exports 不要写在一个文件 或 使用@babel/plugin-transform-runtime

7 , vscode vetur 2307 bug: Cannot find module '@/js/util'

github.com/vuejs/vetur…

import xxx from @/xxx/xxx 在.vue文件中提示 vetur 2307 找不到module 。 在.ts文件中正常。

tsconfig path 配置了 "@/*": [ "src/*" ]

解决方法: 用vscode 打开tsconfig所在文件夹。让tsconfig.json处于最外层 即可

7) 当我使用 JavaScript 文件时,为什么我会得到 error TS5055: Cannot write file 'xxx.js' because it would overwrite input file 错误?

对于 TypeScript 文件来说,在默认情况下,编译器将在同一目录中生成与 JavaScript 相同文件名的文件。因为 TypeScript 文件与编译后的文件总是拥有不同的后缀,这么做是安全的。然而,如果你设置 allowJs 编译选项为 true 和没有设置任何的编译输出属性(outFile 和 outDir),编译器将会尝试使用相同的规则来编译文件,这将导致发出的 JavaScript 文件与源文件具有相同的文件名。为了避免意外覆盖源文件,编译器将会发出此警告,并跳过编写输出文件。

有多种方法可以解决此问题,但所有这些方法都涉及配置编译器选项,因此建议你在项目根目录中的 tsconfig.json 文件来启用此功能。如果你不想编译 JavaScript 文件,你只需要将 allowJs 选项设置为 false;如果你确实想要包含和编译这些 JavaScript 文件,你应该设置 outDir 或者 outFile 选项,定向到其他位置,这样他们就不会与源文件冲突。如果你仅仅是想包含这些 JavaScript 文件,但是不需要编译,设置 noEmit 选项为 true 可以跳过编译检查。