web-dev-qa-db-ja.com

TypeScript 2:型付けされていないnpmモジュールのカスタム型付け

他の場所 に投稿された提案を試した後、型指定されていないNPMモジュールを使用するTypeScriptプロジェクトを実行できません。以下は最小限の例と私が試した手順です。

この最小限の例では、lodashに既存の型定義がないと仮定します。そのため、パッケージ@types/lodashを無視し、そのタイピングファイルlodash.d.tsをプロジェクトに手動で追加しようとします。

フォルダー構造

  • node_modules
    • ロダシュ
  • src
    • foo.ts
  • タイピング
    • カスタム
      • lodash.d.ts
    • グローバル
    • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json

次に、ファイル。

ファイルfoo.ts

///<reference path="../typings/custom/lodash.d.ts" />
import * as lodash from 'lodash';

console.log('Weeee');

ファイルlodash.d.tsは、元の@types/lodashパッケージから直接コピーされます。

ファイルindex.d.ts

/// <reference path="custom/lodash.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />

ファイルpackage.json

{
  "name": "ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "typings": "./typings/index.d.ts",
  "dependencies": {
    "lodash": "^4.16.4"
  },
  "author": "",
  "license": "ISC"
}

ファイルtsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "typeRoots" : ["./typings"],
    "types": ["lodash"]
  },
  "include": [
    "typings/**/*",
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

ファイルtypings.json

{
    "name": "TestName",
    "version": false,
    "globalDependencies": {
        "lodash": "file:typings/custom/lodash.d.ts"
    }
}

ご覧のとおり、タイピングをインポートするさまざまな方法を試しました。

  1. foo.tsに直接インポートすることにより
  2. package.jsontypingsプロパティによって
  3. ファイルtsconfig.jsontypings/index.d.tstypeRootsを使用する
  4. tsconfig.jsonで明示的なtypesを使用することにより
  5. tsconfig.jsontypesディレクトリを含めることにより
  6. カスタムtypings.jsonファイルを作成し、typings installを実行する

それでも、TypeScriptを実行すると:

E:\temp\ts>tsc
error TS2688: Cannot find type definition file for 'lodash'.

何が間違っていますか?

80
Jodiug

残念ながら、これらのことは現在あまりよく文書化されていませんが、それを機能させることができたとしても、各部分が何をしているのか、TypeScriptがタイピングをどのように処理しロードするかとどう関係するのかを理解するために設定を見ていきましょう。

最初に、受信しているエラーを調べてみましょう。

error TS2688: Cannot find type definition file for 'lodash'.

このエラーは、実際には、インポートまたは参照、またはtsファイル内のどこでもlodashを使用しようとしたことが原因ではありません。むしろ、typeRootsプロパティとtypesプロパティの使用方法の誤解から来ているので、それらについてもう少し詳しく見ていきましょう。

typeRoots:[]およびtypes:[]プロパティに関することは、これらがではなくの任意の宣言(*.d.ts)ファイルをロードする汎用的な方法であることです。

これら2つのプロパティは、NPM packagesから入力宣言をパッケージ化およびロードできる新しいTS 2.0機能に直接関連しています。

これは、NPM形式のフォルダー(つまりpackage.jsonまたはindex.d.ts)。

typeRootsのデフォルトは次のとおりです。

{
   "typeRoots" : ["node_modules/@types"]
}

デフォルトでは、これはTypeScriptがnode_modules/@typesフォルダーに入り、そこで見つかったすべてのサブフォルダーをnpm packageとしてロードしようとすることを意味します。

フォルダーにnpmパッケージのような構造がない場合、これは失敗することを理解することが重要です。

これがあなたのケースで起こっていることであり、初期エラーの原因です。

TypeRootを次のように切り替えました。

{
    "typeRoots" : ["./typings"]
}

これは、TypeScriptが./typingsフォルダーでsubfoldersをスキャンし、見つかった各サブフォルダーをnpmモジュールとしてロードしようとすることを意味します。

それでは、./typingsを指すtypeRootsのセットアップがあったが、まだtypes:[]のプロパティがセットアップされていないふりをしましょう。次のエラーが表示される可能性があります。

error TS2688: Cannot find type definition file for 'custom'.
error TS2688: Cannot find type definition file for 'global'.

これは、tsc./typingsフォルダーをスキャンして、サブフォルダーcustomおよびglobalを検出しているためです。次に、これらをnpmパッケージタイプのタイピングとして解釈しようとしていますが、これらのフォルダーにはindex.d.tsまたはpackage.jsonがないため、エラーが発生します。

ここで、設定しているtypes: ['lodash']プロパティについて少し話しましょう。これは何をしますか?デフォルトでは、TypeScriptは、typeRoots内で見つかったallサブフォルダーをロードします。 types:プロパティを指定すると、それらの特定のサブフォルダーのみが読み込まれます。

あなたの場合、./typings/lodashフォルダーをロードするように伝えていますが、存在しません。これがあなたが得る理由です:

error TS2688: Cannot find type definition file for 'lodash'

それで、私たちが学んだことを要約しましょう。 TypeScript 2.0では、npm packagesにパッケージ化された宣言ファイルをロードするためのtypeRootsおよびtypesが導入されました。 npmパッケージの規則に従ってフォルダーに含まれていないカスタムタイピングまたは単一の緩いd.tsファイルがある場合、これらの2つの新しいプロパティは使用するものではありません。 TypeScript 2.0は、これらの消費方法を実際には変更しません。多くの標準的な方法のいずれかで、これらのファイルをコンパイルコンテキストに含める必要があります。

  1. .tsファイルに直接含める:///<reference path="../typings/custom/lodash.d.ts" />

  2. ./typings/custom/lodash.d.tsプロパティにfiles: []を含める。

  3. ./typings/index.d.tsプロパティにfiles: []を含める(その後、他のタイピングを再帰的に含みます)。

  4. ./typings/**includes:に追加する

この議論に基づいて、tsconfig.jsonに変更を加えたことが原因で再び機能するようになった理由がわかることを願っています。

編集:

私が言及するのを忘れていた1つのことは、typeRootstypesプロパティは、グローバル宣言の自動ロードにのみ実際に有用であることです。

たとえば

npm install @types/jquery

そして、デフォルトのtsconfigを使用している場合、jqueryタイプのパッケージが自動的にロードされ、$///<reference/>またはimportをさらに行う必要のないすべてのスクリプトで利用可能になります

typeRoots:[]プロパティは、タイプpackagesが自動的に読み込まれる場所を追加することを目的としています。

types:[]プロパティの主な使用例は、自動ロード動作を無効にして(空の配列に設定することにより)、グローバルに含めたい特定のタイプのみをリストすることです。

さまざまなtypeRootsから型パッケージをロードする別の方法は、新しい///<reference types="jquery" />ディレクティブを使用することです。 typesではなくpathに注意してください。繰り返しますが、これはグローバルな宣言ファイル、通常はimport/exportを実行しないファイルにのみ役立ちます。

ここで、typeRootsとの混乱を引き起こすものの1つを示します。 typeRootsはモジュールのグローバルな包含に関するものだと言ったことを思い出してください。ただし、@types/folderは標準モジュールの解決にも関係します(typeRoots設定に関係なく)。

具体的には、モジュールを明示的にインポートすると、常にincludesexcludesfilestypeRoots、およびtypesオプションがすべてバイパスされます。あなたがそうするとき:

import {MyType} from 'my-module';

上記のプロパティはすべて完全に無視されます。 モジュール解決中の関連プロパティは、baseUrlpaths、およびmoduleResolutionです。

基本的に、nodeモジュール解決を使用する場合、baseUrl構成で指定されたフォルダーからファイル名my-module.tsmy-module.tsxmy-module.d.tsの検索を開始します。

ファイルが見つからない場合は、my-moduleという名前のフォルダーを探し、typingsプロパティを持つpackage.jsonを検索します。package.jsonが存在する場合、またはtypingsプロパティをロードするファイルを指定すると、index.ts/tsx/d.tsが検索されますそのフォルダ内。

それでもうまくいかない場合は、node_modulesで始まるbaseUrl/node_modulesフォルダーで同じものを検索します。

さらに、これらが見つからない場合は、baseUrl/node_modules/@typesで同じものをすべて検索します。

それでも何も見つからなかった場合は、親ディレクトリに移動し、node_modulesnode_modules/@typesを検索します。ファイルシステムのルートに到達するまでディレクトリを上に移動し続けます(プロジェクトの外にノードモジュールを取得することもあります)。

私が強調したいことの1つは、モジュールの解決は、設定したtypeRootsを完全に無視することです。したがって、typeRoots: ["./my-types"]を構成した場合、明示的なモジュール解決中にこれは検索されません。インポートまたは参照することなく、アプリケーション全体で使用できるようにするグローバル定義ファイルを配置できるフォルダーとしてのみ機能します。

最後に、パスマッピング(つまり、pathsプロパティ)でモジュールの動作をオーバーライドできます。したがって、たとえば、モジュールを解決しようとするときに、カスタムtypeRootsは参照されないことに言及しました。しかし、もしあなたが好きなら、この動作を次のように実行できます

"paths" :{
     "*": ["my-custom-types/*", "*"]
 }

これは、左側と一致するすべてのインポートに対して行われます。インポートを含める前に、右側のようにインポートを変更してみてください(右側の*は、最初のインポート文字列を表します。たとえば、インポートする場合:

import {MyType} from 'my-types';

あなたが書いたように最初にインポートを試みます:

import {MyType} from 'my-custom-types/my-types'

そして、それが見つからなかった場合、接頭辞なしで再試行します(配列の2番目の項目は、最初のインポートを意味する*です。

したがって、この方法では、追加のフォルダーを追加して、カスタム宣言ファイル、またはimportにしたいカスタム.tsモジュールを検索できます。

特定のモジュールのカスタムマッピングを作成することもできます。

"paths" :{
   "*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
 }

これはあなたにさせます

import {MyType} from 'my-types';

しかし、それらの型をsome/custom/folder/location/my-awesome-types-file.d.tsから読み取ります

169
dtabuenc

編集:古い。上記の答えを読んでください。

私はまだこれを理解していませんが、解決策を見つけました。次のtsconfig.jsonを使用します。

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "*": [
        "./typings/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

typings.jsonと、lodash.d.tsを除くフォルダーtypingsの下のすべてを削除します。すべての///...参照も削除します

6
Jodiug

"*": ["./types/*"] tsconfigパスのこの行は、2時間の闘争の後、すべてを修正しました。

{
  "compilerOptions": {
    "moduleResolution": "node",
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "*": ["./types/*"]
    },
    "jsx": "react",
    "types": ["node", "jest"]
  },
  "include": [
    "client/**/*",
    "packages/**/*"
  ],
  "exclude": [
    "node_modules/**/*"
  ]
}

typesは、node_moduleの横にあるフォルダー名です。つまり、clientフォルダー(またはのレベル) srcフォルダー)types/third-party-lib/index.d.ts
index.d.tsにはdeclare module 'third-party-lib';があります

注:上記の設定は不完全な設定であり、タイプ、パス、インクルードおよびエクスクルードでどのように見えるかのアイデアを提供するだけです。

1
Uday Sravan K