当前位置: 首页 > Web前端 > HTML5

Vue2.5+迁移到Typescript指南

时间:2023-04-04 23:38:06 HTML5

Vue2.5+迁移到Typescript指南为什么要迁移到TypescriptJavascript本身是一种动态的弱类型语言。此功能导致Javascript代码中出现大量UncaughtTypeError错误。无论是调试还是在线代码稳定性都带来了很多负面影响。Typescript提供了静态类型检查,这样很多类型错误在写的时候就已经发现了,不会带到测试阶段。同时,Javascript可以在不定义模型的情况下使用对象。有些人喜欢这种灵活性。诚然,这样的语法在模型不复杂的时候可以快速开发出需要的功能,但是一旦模型庞大,就很难找到需要的属性值。不知道从哪里开始。在Typescript中,我们需要使用TS中的接口类型来定义模型,然后才能调用它的属性值,所以Typescript大大提高了代码的可读性。可行性因为TypeScript是JavaScript的超集,所以TypeScript不会阻止JavaScript运行,即使出现类型错误,这可以让你的JavaScript逐渐迁移到TypeScript。所以你可以慢慢地进行迁移,一次一个模块,选择一个模块,将.js文件重命名为.ts,在代码中添加类型注释。完成此模块后,选择下一个模块。如何将已有的Vue项目迁移到Typescript安装依赖Vue官方提供了一个库Vue-class-component,可以让我们使用Ts的类声明方式编写Vue组件代码。Vue-property-decorator提供了一种基于Vue-class-component编写代码的方式。首先我们需要在package.json中引入这两个依赖。我的项目是基于vue-cli@3.X创建的,我还需要在项目中引入@vue/cli-plugin-typescripttypescript两个依赖来完成Typescript的编译。配置tsconfig.json在项目根目录新建tsconfig.json,引入如下代码{"compilerOptions":{"target":"esnext","module":"esnext","strict":true,"jsx":"preserve","importHelpers":true,"moduleResolution":"node","experimentalDecorators":true,"esModuleInterop":true,"allowSyntheticDefaultImports":true,"sourceMap":true,"baseUrl":".","noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitReturns":true,"noImplicitThis":true,"types":["webpack-env"],"paths":{"@/*":["./app/common/*"],"_app/*":["./app/*"],"_c/*":["./app/common/components/*"],"api/*":["./app/service/*"],"assets/*":["./app/assets/*"]},"lib":["esnext","dom","dom.iterable","scripthost"],},"include":[//这里根据你项目中的typescript填写需要编译的文件路径"app/**/*.ts","app/**/*.tsx","app/**/*.d.ts","app/**/*.vue",],"exclude":["node_modules"]}特别是现在的vue项目大多使用webpack的别名用于解析路径。tsconfig.json中需要配置path属性,这样typescript也可以识别webpack中配置的路径别名。添加全局声明文件因为vue文件在ts文件中无法识别,所以需要在项目根目录新建shims-vue.d.ts文件,添加如下代码让ts识别vue文件.importVuefrom'vue';declaremodule'*.vue'{exportdefaultVue;}自下而上的迁移因为是现有项目的迁移,不建议一开始就把main.js重命名为main.ts,对于大多数Vue项目,main.js引入了太多的依赖项。我们应该从依赖开始,从下往上迁移Typescript。对于项目中的一些低级库函数,即使是框架维护者提供的库函数,我们也不关心它们的实现逻辑,所以不需要重写成ts文件,只需要在里面加上声明文件即可我们的业务代码来调用。在我的项目中,service层的逻辑很简单。它只是传递参数来调用接口,没有添加任何其他逻辑。逻辑很简单,没必要改写成ts文件,所以我写了一个服务层文件的声明文件。为调用服务层的代码提供类型声明。声明文件写法一个js文件如下accountType可选*@param{String}data.username*@param{String}data.password*@param{String}data.genderX|女|M*@param{String}data.email*@param{Number}data.level*/createAccount(data){returnaxios.request({url:`/api/account/createUser`,方法:'post',数据:数据}).then((res)=>[res,null]).catch((err)=>[null,err]);},}可以看到在使用typescript之前,函数的参数、返回值等信息的提示都是通过jsdoc实现的,可以在调用Type和name的时候判断参数,但是jsdoc毕竟只是注释而已,并且不能提供类型验证,所以这里我们为其编写一个声明文件,编写的声明文件如下//service.d.tsinterfacecreateAccountParams{accountType?:string,username:string,password:string,gender:'X'|'F'|'M',email:string,level?:number}interfacecreateAccountReturn{userId:string,}exportinterfaceService{createAccount(data:createAccountParams):createAccountReturn}服务层接口文件声明文件完成。我们经常将service.js导出的实例绑定到main.js中的Vue原型上,这样我们就可以在vue组件中,通过vm.$service来方便的访问服务实例,但是Typescript不知道是什么属性在Vue实例上。这时候我们需要在之前添加的shims-vue.d.ts文件中添加几行代码。从“vue”导入Vue;从“pathToService/service.d.ts”导入服务;声明模块“*.vue”{导出默认Vue;}声明模块“vue/types/vue”{接口Vue{$service:服务}}得益于typescript提供的模块补充功能,我们可以在node_modules/vue/types/vue中补充我们需要在Vue上提供的属性。改写vue文件,我们需要改写原来要使用vue-property-decorator编写的vue文件。至此,一个Vue项目迁移到Typescript的过程就完成了,剩下的工作就是一步步将代码中的其他文件从js迁移到typescript。将方法绑定到Vue实例上除了我们之前提到的在Vue实例上挂载我们写的服务之外,大家一定知道在Vue项目中,我们经常会调用this.$refsthis.$routerthis.$store等.,typescript也会检查这些属性是否绑定到vue实例,那我们没有在类型系统中声明这些值,应该会报Property'$refs'doesnotexistontype[your_component_name]真相吧$refsvue-routervuex已经帮我们声明了对应的type,我们可以cd./node_modules/vue/types/目录查看,截取少量代码如下:exportinterfaceVue{readonly$el:Element;只读$options:ComponentOptions;只读$parent:Vue;只读$root:Vue;只读$children:Vue[];只读$refs:{[key:string]:Vue|元素|视图[]|元素[]};只读$slots:{[key:string]:VNode[]|不明确的};只读$scopedSlots:{[key:string]:NormalizedScopedSlot|不明确的};只读$isServer:布尔值;只读$data:Record;只读$props:Record;只读$ssrContext:任何;只读$vnode:VNode;只读$attrs:Record;只读$listeners:Record;}只要vue-routervuex正常安装在dependencies中,类型已经通过模块补充添加到vue实例中。在某些项目中,vue-routervuex的依赖并没有通过安装在依赖中引入,而是通过index.html导入的cdn资源文件,使得我们在开发过程中无法获取其类型。这时候,我们可以通过安装@types依赖,将类型系统添加到项目中,比如npminstall@types/jquery--save-dev。不幸的是,vue-router和vuex的类型包已经被废弃了。只能手动从github下载对应版本的vue-routervuex,将types文件引入到项目中。你可以像我一样在项目中创建一个新的类型目录。,导入所需的类型声明文件。这样就可以在vue实例上直接访问$store$router等属性。当你想从其他组件库中导入一些类型文件时也是如此。一些需要注意的问题。在Vue的开发过程中,我们会使用this.$refs来访问具体实例的方法,但是在ts中并不常见。例如,如果要在form组件中使用validate方法,我们需要为其添加类型断言this.$refs.form.validate()变为(this.$refs.formasVue&{validate:Function}).validate()告诉编译器this.$refs。表单上有一个验证方法。因为类型断言的前提是当类型S是类型T的子集,或者类型T是类型S的子集时,S才能成功断言为T,所以在类型断言时需要合并Vue类型。同时,我们也可以通过vue-property-decoratorimport{Vue,Component,Ref}from'vue-property-decorator'importFormfrom提供给我们的装饰器,一劳永逸地将refs添加到计算属性中'@/path/to/another-component.vue'@ComponentexportdefaultclassYourComponentextendsVue{@Ref()readonlyform!:Form}等价于exportdefault{computed(){form:{cache:false,get(){returnthis.$refs.formasForm}},}}这样我们就可以使用this.form.validate()来做表单验证了。新手容易遇到的一些问题问题一:接口和类型有什么区别?type可以声明基本类型别名、联合类型、元组和其他类型eg.typea=string;允许,接口将自动声明和合并接口人{性别:字符串年龄:数字}接口人{名称:字符串}问题2:错误属性'hideContent'没有初始化器并且在构造函数中没有明确分配。strictPropertyInitialization属性将是当strict设置为true时自动设置为true。但是这个属性是不合理的。它要求每个实例的属性都有一个初始值。我们只是在tsconfig中将其设置为false。问题3:assignmentcompatibilityinterfaceperson{name:stringage:number}interfacestudent{name:stringage:numberstuid:string}letperson:person={name:'name',age:1}letstudent:student={name:'name',age:1,stuid:'stuid'};person=student//这个可以student=person//这个不允许续,欢迎补充