TypeScrip の再構成の問題と解決策

不言
リリース: 2018-07-25 10:08:47
オリジナル
2794 人が閲覧しました

この記事で共有する内容は、TypeScript の変換の問題と解決策についてのものです。次に、具体的な内容を見てみましょう。

概要

この変換プロジェクトは NPM を通じて公開される基本的なサービス パッケージであるため、TypeScript を使用したこの変換の目標は、Babel ファミリ バケットを削除し、パッケージ サイズを削減し、強力な型制約を追加することです。これにより、起こり得る問題が回避されます。将来の開発において。

この変換では、パッケージ化とコンパイルに TypeScript v2.9.2 と Webpack v4.16.0 を使用します。開発ツールは VSCode を使用し、中国語言語パックを使用します。予想される目標は、ローダーを通じて TypeScript コードを ES5 コードに直接コンパイルすることです。

この記事に含まれる問題の一部は TypeScript の構成と使用法の問題であり、一部は VSCode 自体の構成に関連しています。

改革の問題の記録と分析

VSCode関連

「関連モジュールが見つかりません」エラー

プロジェクトでwebpack.aliasを使用すると、モジュールが見つからないというメッセージが表示される場合があります。

具体的なエラーは次のとおりです:

终端编译报错:TS2307: Cannot find module '_utils/index'.
编辑器报错:[ts]找不到模块“_utils/index”。
ログイン後にコピー

これは、エディターが対応するエイリアス情報を読み取れないことが原因で発生します。

この時点で、対応するモジュールが存在するかどうかを確認する必要があります。モジュールが存在することが確認され、ターミナルのコンパイル中にエラーが報告されないにもかかわらず、エディターによってエラーのみが報告される場合、それはエディターが Webpack 構成を読み取ることができないためであり、追加の構成を追加する必要があります。

解決策: webpack.alias の構成に加えて、対応する tsconfig.json も構成する必要があります。具体的な構成は次のとおりです: 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不允许增加没有声明的属性。

因此,我们有两个办法来解决这个报错:

  1. 在对象中增加属性定义(推荐)。具体方式为:let a = {b: void 0};。这个方法能够从根本上解决当前问题,也能够避免对象被随意赋值的问题。

  2. a对象增加any属性(应急)。具体方式为:let a: any = {};。这个方法能够让TypeScript类型检查时忽略这个对象,从而编译通过不报错。这个方法适用于大量旧代码改造的情况。

Window对象属性赋值报错

与上一个情况类似,我们给一个对象中赋值一个不存在的属性,会出现编辑器和编译报错:

window.a = 1;
// 终端编译报错:TS2339: Property 'a' does not exist on type 'Window'.
// 编辑器报错:[ts] 类型“Window”上不存在属性“a”。
ログイン後にコピー

这也是因为TypeScript不允许增加没有声明的属性导致的。

由于我们没有办法声明windows属性的值(或者说很困难),因此我们需要通过下面这一种方式来解决:

  1. 我们在windows使用时增加一个类型转换,即(window as any).a = 1;。这样就能够保证编辑器和编译时不会出错。不过该方法只建议用于旧项目改造,我们还是要尽量避免在window对象上面增加属性,应该通过一个全局的数据管理器来进行数据存取。

ES2015 Object新增的原型链上的方法报错

在项目中,使用到了一些Object原型链上面的一些ES2015新增的方法,如Object.assignObject.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');

终端编译报错:TS2693: 'Map' only refers to a type, but is being used as a value here.
编辑器报错报错:[ts] “Map”仅表示类型,但在此处却作为值使用。
ログイン後にコピー
注: tsconfig の場合。今後も json がエラーを報告する場合は、VSCode がプロジェクトのロード時にのみ関連する構成情報を読み取ると考えられます。 JavaScript プロジェクトの jsconfig.json にも同じことが当てはまります。

TypeScript 関連

オブジェクト属性割り当てエラー

JavaScript では、空のオブジェクトを宣言して、この属性に値を割り当てることがよくあります。ただし、この操作により TypeScript:🎜
终端编译报错: TS2693: 'Promise' only refers to a type, but is being used as a value here.
编辑器报错:[ts] “Promise”仅表示类型,但在此处却作为值使用。
ログイン後にコピー
ログイン後にコピー
🎜 でエラーが発生します。これは、TypeScript では宣言されていない属性の追加が許可されていないためです。 🎜🎜したがって、このエラーを解決するには 2 つの方法があります: 🎜
  1. 🎜 オブジェクトに属性定義を追加します (推奨)。具体的なメソッドは次のとおりです: let a = {b: void 0};。 この方法は、現在の問題を根本的に解決し、オブジェクトがランダムに割り当てられる問題を回避できます。 🎜
  2. 🎜 a オブジェクトに任意の属性を追加します (緊急)。具体的なメソッドは次のとおりです: let a: any = {};。このメソッドを使用すると、TypeScript は型チェック中にこのオブジェクトを無視できるため、コンパイル中にエラーは報告されません。この方法は、大量の古いコード変換に適しています。 🎜
🎜🎜ウィンドウ オブジェクトの属性割り当てエラー 🎜🎜🎜前の状況と同様に、存在しない属性をオブジェクトに割り当てると、エディターおよびコンパイル エラーが表示されます: 🎜
"compilerOptions": {
    "lib": ["es2015.promise"]
}
ログイン後にコピー
ログイン後にコピー
🎜これはこれは、TypeScript では未宣言のプロパティの追加が許可されていないためです。 🎜🎜windows 属性の値を宣言する方法がない (または非常に難しい) ため、次の方法で解決する必要があります: 🎜
  1. 🎜私たちは Windows を使用しています。使用するときに型変換を追加します。つまり、(window as any).a = 1; です。これにより、エディター内およびコンパイル中にエラーが発生しないことが保証されます。ただし、この方法は古いプロジェクトを改修する場合にのみ推奨されます。データにはグローバル データ マネージャーを介してアクセスする必要があります。 🎜
🎜🎜プロトタイプ チェーン上の ES2015 オブジェクトの新しいメソッドがエラーを報告します🎜🎜🎜 プロジェクトでは、Object など、オブジェクト プロトタイプ チェーン上のいくつかの ES2015 の新しいメソッドが使用されています。 code> や <code>Object.values など、この時点でコンパイルは失敗し、VSCode はエラーを表示します: 🎜
终端编译报错:TS2304: Cannot find name 'setTimeout'.
编辑器报错:[ts] 找不到名称“setTimeout”。
ログイン後にコピー
ログイン後にコピー
🎜これは、tsconfig.json で指定したためです。 > target は ES5 であり、TypeScript には関連するポリフィルがないため、ES2015 では新しいメソッドを使用できません。 🎜🎜解決策: lodash ツール セットの関連メソッドを使用できます。インストール中に lodash.assign@types/lodash.assign をインストールする必要があります。 lodash.assign は CMD 標準パッケージであり、import _assign = require('lodash.assing'); を通じて導入する必要があります。 🎜🎜🎜ES2015 の新しいデータ構造マップの初期化エラー🎜🎜🎜ES2015 コードを TypeScript コードに変換するとき、ES2015 で新しい Map タイプを使用すると、エディターまたはターミナルのコンパイル時にエラーが報告されます: 🎜
"compilerOptions": {
    "lib": ["dom"]
}
ログイン後にコピー
ログイン後にコピー
🎜これはTypeScript は関連するデータ型を提供しておらず、対応するポリフィルがないためです。 🎜🎜したがって、この問題を解決するための 3 つのアイデアがあります: 🎜
  1. tsconfig.json配置中的target属性改为es6,即输出符合ES2015规范的代码。因为ES2015存在全局的Promise对象,因此编译和编辑器都不会报错。该方法优点为配置简单,无需改动代码,缺点为需要高级浏览器的支持或者Babel全家桶的支持。

  2. 舍弃Map类型,改用Object进行替代。这种改造比较费时费力,适用于工作量较小和不愿意引入其他文件的场景。

  3. 自行实现或者安装一个Map包。这种方法改造成本较小,缺点就是会引入额外的代码或者包,并且代码效率无法保证。例如ts-maptypescript-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。

因此,我们解决这个问题的思路仍然有三种:

  1. tsconfig.json配置文件配置中的target属性改为es6,即输出符合ES2015规范的代码。因为ES2015存在全局的Promise对象,因此编译和编辑器都不会报错。该方法优点为配置简单,无需改动代码,缺点为需要高级浏览器的支持或者Babel全家桶的支持。

  2. 引入一个Promise库,如bluebird等比较知名的Promise库。在安装bluebird时需要同时安装@types/bluebird声明文件。缺点就是引入的Promise库较大,而且如果你的库作为一个基础库时,可能会与其他的调用方的Promise库产生冲突。

  3. tsconfig.json配置文件中增加lib。此方法的原理是让TypeScript编译时引用外部的Promise对象,因此在编译时不会报错。此方式优点是不会引入任何其他代码,但是缺点是一定要保证在引用此库的前提下,一定存在Promise对象。具体配置如下:

    "compilerOptions": {
        "lib": ["es2015.promise"]
    }
    ログイン後にコピー
    ログイン後にコピー

SetTimeout使用报错

将ES2015代码改造成TypeScript代码时,如果使用了setTimeout和setInterval函数时,可能会出现无法找到该函数的报错:

终端编译报错:TS2304: Cannot find name 'setTimeout'.
编辑器报错:[ts] 找不到名称“setTimeout”。
ログイン後にコピー
ログイン後にコピー

这是由于编辑器和编译时不知道当前代码运行环境导致的。

因此,我们解决这个问题的思路有两种:

  1. tsconfig.json配置文件中增加lib。让TypeScript能够知道当前的代码容器。具体示例如下:

    "compilerOptions": {
        "lib": ["dom"]
    }
    ログイン後にコピー
    ログイン後にコピー
  2. 安装@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] 应为声明或语句。
ログイン後にコピー

这是由于两者的模块语法不一样导致的。

因此,我们解决这个问题只需要用下面这一种方法:

  1. 将上面的export from的语法稍加调整来适配TypeScript语法。具体改造如下:

    export {default as Session} from '_models/session'; //调整后不报错
    export * from '_models/read-item';// 之前不报错不需要调整
    ログイン後にコピー

总结

在做项目TypeScript改造的过程中,遇到了不少大大小小的坑。很多问题在网上都没有解决方案或者没有说明白具体的解决步骤,因此希望通过这一篇文章来帮助大家在进行TypeScript迁移时避免在我踩过的坑上再浪费时间。

相关推荐:

关于TypeScript在node项目中的实践分析

以上がTypeScrip の再構成の問題と解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート