The content shared with you in this article is about TypeScript transformation problems and solutions. The content is very detailed. Next, let’s take a look at the specific content. I hope it can help everyone.
Since this transformation project is a basic service package published through NPM, the goal of this transformation using TypeScript is to remove the Babel family Bucket, reduce package size, and add strong type constraints to avoid possible problems in future development.
This transformation uses TypeScript v2.9.2 and Webpack v4.16.0 for packaging and compilation. The development tool uses VSCode and uses the Chinese language pack. The expected goal is to directly compile TypeScript code into ES5 code through the loader.
Some of the issues involved in this article are TypeScript configuration and usage issues, and some are issues related to the configuration of VSCode itself.
In the project, if we use webpack.alias, we may be prompted that the module cannot be found.
The specific errors are as follows:
终端编译报错:TS2307: Cannot find module '_utils/index'. 编辑器报错:[ts]找不到模块“_utils/index”。
This is caused by the editor being unable to read the corresponding alias information.
At this point we need to check whether the corresponding module exists. If it is confirmed that the module exists and no error is reported during terminal compilation, but only an error is reported by the editor, it is because the editor cannot read the webpack configuration and we need to add additional configuration.
Solution: In addition to configuring webpack.alias, you also need to configure the corresponding tsconfig.json
. The specific configuration is as follows:
"compilerOptions": { "baseUrl": ".", "paths": { "_util/*": [ "src/core/utils/*" ] } }
Note: If If you still get an error after configuring tsconfig.json
, you need to restart VSCode. It is speculated that VSCode only reads relevant configuration information when the project is loaded. The same goes for jsconfig.json
in JavaScript projects.
In JavaScript, we often declare an empty object , and then assign a value to this attribute. However, this operation will cause an error when placed in TypeScript:
let a = {}; a.b = 1; // 终端编译报错:TS2339: Property 'b' does not exist on type '{}'. // 编辑器报错:[ts] 类型“{}”上不存在属性“b”。
This is because TypeScript does not allow adding undeclared attributes.
Therefore, we have two ways to solve this error:
Add attribute definitions to the object (recommended). The specific method is: let a = {b: void 0};.
This method can fundamentally solve the current problem and avoid the problem of objects being randomly assigned.
Add any attribute to the a
object (emergency). The specific method is: let a: any = {};
. This method allows TypeScript to ignore this object during type checking, so that no error is reported during compilation. This method is suitable for large amounts of old code transformation.
Similar to the previous situation, when we assign a non-existent attribute to an object, an edit will appear The compiler and compiler reported an error:
window.a = 1; // 终端编译报错:TS2339: Property 'a' does not exist on type 'Window'. // 编辑器报错:[ts] 类型“Window”上不存在属性“a”。
This is also caused by the fact that TypeScript does not allow adding undeclared attributes.
Since we have no way to declare the value of the windows attribute (or it is very difficult), we need to solve it in the following way:
We use in windows Add a type conversion, that is (window as any).a = 1;
. This ensures that there will be no errors in the editor and during compilation. However, this method is only recommended for the renovation of old projects. We should try to avoid adding attributes to the window object. Data should be accessed through a global data manager.
In the project, some ES2015 new methods on the Object prototype chain are used Added methods, such as Object.assign
and Object.values
, etc., the compilation will fail at this time, and VSCode will prompt an error:
终端编译报错:TS2339: Property 'assign' does not exist on type 'ObjectConstructor'. 编辑器报错:[ts] 类型“ObjectConstructor”上不存在属性“assign”。
This is because we are The target
specified in tsconfig.json
is ES5, and TypeScript does not have the relevant polyfill, so we cannot use the new methods in ES2015.
Solution: You can use the related methods in the lodash tool set. You need to install lodash.assign
and @types/lodash.assign
during installation. And lodash.assign
is a CMD specification package and needs to be introduced through import _assign = require('lodash.assing');
.
When transforming ES2015 code into TypeScript code, if you use the new Map type in ES2015, then An error will be reported when compiling in the editor or terminal:
终端编译报错:TS2693: 'Map' only refers to a type, but is being used as a value here. 编辑器报错报错:[ts] “Map”仅表示类型,但在此处却作为值使用。
This is because TypeScript does not provide relevant data types and there is no corresponding polyfill.
Therefore, we have three ideas to solve this problem:
将tsconfig.json
配置中的target
属性改为es6
,即输出符合ES2015规范的代码。因为ES2015存在全局的Promise对象,因此编译和编辑器都不会报错。该方法优点为配置简单,无需改动代码,缺点为需要高级浏览器的支持或者Babel全家桶的支持。
舍弃Map类型,改用Object进行替代。这种改造比较费时费力,适用于工作量较小和不愿意引入其他文件的场景。
自行实现或者安装一个Map包。这种方法改造成本较小,缺点就是会引入额外的代码或者包,并且代码效率无法保证。例如ts-map
和typescript-map
,这两个包的查找效率都是o(n),低于原生类型的Map。因此推荐自己使用Object实现一个简单的Map,具体实现方式可以去网上找相关的Map原理分析与实践(大致原理为使用多个Object,存储不同类型元素时使用不同容器,避免类型转换问题)。
将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"] }
将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迁移时避免在我踩过的坑上再浪费时间。
相关推荐:
The above is the detailed content of TypeScrip reshaping problems and solutions. For more information, please follow other related articles on the PHP Chinese website!