您好,欢迎访问一九零五行业门户网

TypeScrip的重新改造问题以及解决问题的方案

本篇文章分享给大家的内容是关于typescript改造问题与解决方案,内容很详细,接下来我们就来看看具体的内容,希望可以帮助到大家。
概述由于本次改造的项目为一个通过npm进行发布的基础服务包,因此本次采用typescript进行改造的目标是移除babel全家桶,减小包体积,同时增加强类型约束从而避免今后开发时可能的问题。
本次改造使用的是typescript v2.9.2,采用webpack v4.16.0进行打包编译。开发工具使用的是vscode,使用中文语言包。预期目标是直接将typescript代码通过loader直接编译为es5的代码。
本文中涉及的问题有部分是typescript配置和使用的问题,也有部分是vscode本身配置相关问题。
改造问题记录与分析vscode相关“无法找到相关模块”报错在项目中,如果我们使用了webpack.alias,可能会提示找不到模块。
具体错误如下:
终端编译报错:ts2307: cannot find module '_utils/index'.编辑器报错:[ts]找不到模块“_utils/index”。
这是由于编辑器无法读取对应的别名信息导致的。
此时我们需要检查对应的模块是否存在。如果确认模块存在,且终端编译编译时不报错,而只是编辑器报错,则是因为编辑器无法读取webpack配置,我们需要增加另外的配置。
解决方法:除了配置webpack.alias,还需要配置相对应的tsconfig.json,具体配置如下所示:
compileroptions: {    baseurl: .,    paths: {        _util/*: [            src/core/utils/*        ]    }}
注:如果配置了tsconfig.json以后还是报错的话,需要重启下vscode,猜测是由于vscode只在项目加载时读取相关配置信息。在javascript项目中的jsconfig.json同理。
typescript相关对象属性赋值报错在javascript中,我们经常会声明一个空对象,然后再给这个属性进行赋值。但是这个操作放在typescript中是会发生报错的:
let a = {};a.b = 1;// 终端编译报错:ts2339: property 'b' does not exist on type '{}'.// 编辑器报错:[ts] 类型“{}”上不存在属性“b”。
这是因为typescript不允许增加没有声明的属性。
因此,我们有两个办法来解决这个报错:
在对象中增加属性定义(推荐)。具体方式为:let a = {b: void 0};。这个方法能够从根本上解决当前问题,也能够避免对象被随意赋值的问题。
给a对象增加any属性(应急)。具体方式为:let a: any = {};。这个方法能够让typescript类型检查时忽略这个对象,从而编译通过不报错。这个方法适用于大量旧代码改造的情况。
window对象属性赋值报错与上一个情况类似,我们给一个对象中赋值一个不存在的属性,会出现编辑器和编译报错:
window.a = 1;// 终端编译报错:ts2339: property 'a' does not exist on type 'window'.// 编辑器报错:[ts] 类型“window”上不存在属性“a”。
这也是因为typescript不允许增加没有声明的属性导致的。
由于我们没有办法声明windows属性的值(或者说很困难),因此我们需要通过下面这一种方式来解决:
我们在windows使用时增加一个类型转换,即(window as any).a = 1;。这样就能够保证编辑器和编译时不会出错。不过该方法只建议用于旧项目改造,我们还是要尽量避免在window对象上面增加属性,应该通过一个全局的数据管理器来进行数据存取。
es2015 object新增的原型链上的方法报错在项目中,使用到了一些object原型链上面的一些es2015新增的方法,如object.assign和object.values等,此时编译会失败,同时vscode会提示报错:
终端编译报错:ts2339: property 'assign' does not exist on type 'objectconstructor'.编辑器报错:[ts] 类型“objectconstructor”上不存在属性“assign”。
这是由于我们在tsconfig.json中指定的target是es5,而typescript并没有相关的polyfill,因此我们无法使用es2015中新增的方法。
解决方法:可以使用lodash工具集中的相关方法,安装时需要安装lodash.assign和@types/lodash.assign。并且lodash.assign是一个cmd规范的包,需要通过import _assign = require('lodash.assing');方式引入。
es2015新增的数据结构map初始化报错将es2015的代码改造成为typescript代码时,如果你使用了es2015新增的map类型,那在编辑器还是终端编译中编译时都会报错:
终端编译报错:ts2693: 'map' only refers to a type, but is being used as a value here.编辑器报错报错:[ts] “map”仅表示类型,但在此处却作为值使用。
这是由于typescript并没有提供相关的数据类型,也没有对应的polyfill。
因此,我们解决这个问题的思路有三种:
将tsconfig.json配置中的target属性改为es6,即输出符合es2015规范的代码。因为es2015存在全局的promise对象,因此编译和编辑器都不会报错。该方法优点为配置简单,无需改动代码,缺点为需要高级浏览器的支持或者babel全家桶的支持。
舍弃map类型,改用object进行替代。这种改造比较费时费力,适用于工作量较小和不愿意引入其他文件的场景。
自行实现或者安装一个map包。这种方法改造成本较小,缺点就是会引入额外的代码或者包,并且代码效率无法保证。例如ts-map和typescript-map,这两个包的查找效率都是o(n),低于原生类型的map。因此推荐自己使用object实现一个简单的map,具体实现方式可以去网上找相关的map原理分析与实践(大致原理为使用多个object,存储不同类型元素时使用不同容器,避免类型转换问题)。
es2015新增的promise使用报错将es2015的代码改造成为typescript代码时,如果你使用了es2015的新增的promise类型,那在编辑器还是终端编译编译时都会报错:
终端编译报错: ts2693: 'promise' only refers to a type, but is being used as a value here.编辑器报错:[ts] “promise”仅表示类型,但在此处却作为值使用。
这是由于typescript并没有提供promise数据类型,也没有对应的polyfill。
因此,我们解决这个问题的思路仍然有三种:
将tsconfig.json配置文件配置中的target属性改为es6,即输出符合es2015规范的代码。因为es2015存在全局的promise对象,因此编译和编辑器都不会报错。该方法优点为配置简单,无需改动代码,缺点为需要高级浏览器的支持或者babel全家桶的支持。
引入一个promise库,如bluebird等比较知名的promise库。在安装bluebird时需要同时安装@types/bluebird声明文件。缺点就是引入的promise库较大,而且如果你的库作为一个基础库时,可能会与其他的调用方的promise库产生冲突。
在tsconfig.json配置文件中增加lib。此方法的原理是让typescript编译时引用外部的promise对象,因此在编译时不会报错。此方式优点是不会引入任何其他代码,但是缺点是一定要保证在引用此库的前提下,一定存在promise对象。具体配置如下:
compileroptions: {    lib: [es2015.promise]}
settimeout使用报错将es2015代码改造成typescript代码时,如果使用了settimeout和setinterval函数时,可能会出现无法找到该函数的报错:
终端编译报错:ts2304: cannot find name 'settimeout'.编辑器报错:[ts] 找不到名称“settimeout”。
这是由于编辑器和编译时不知道当前代码运行环境导致的。
因此,我们解决这个问题的思路有两种:
在tsconfig.json配置文件中增加lib。让typescript能够知道当前的代码容器。具体示例如下:
compileroptions: {    lib: [dom]}
安装@types/node。该方法适用于node环境下或者采用webpack打包时可以引入node代码。该方法直接通过npm install @types/node即可安装完成,解决报错问题。
模块引用和导出报错在es2015的代码中,我们可以通过@babel/plugin-proposal-export-default-from插件来直接导出引入的文件,具体示例如下:
export session from './session'; // 报错export * from '_models/read-item'; // 不报错
而在typescript中,这种写法是会报错的:
终端编译报错:ts1128: declaration or statement expected.编辑器报错:[ts] 应为声明或语句。
这是由于两者的模块语法不一样导致的。
因此,我们解决这个问题只需要用下面这一种方法:
将上面的export from的语法稍加调整来适配typescript语法。具体改造如下:
export {default as session} from '_models/session'; //调整后不报错export * from '_models/read-item';// 之前不报错不需要调整
总结在做项目typescript改造的过程中,遇到了不少大大小小的坑。很多问题在网上都没有解决方案或者没有说明白具体的解决步骤,因此希望通过这一篇文章来帮助大家在进行typescript迁移时避免在我踩过的坑上再浪费时间。
相关推荐:
关于typescript在node项目中的实践分析
以上就是typescrip的重新改造问题以及解决问题的方案的详细内容。
其它类似信息

推荐信息