1. ホーム
  2. typescript

[解決済み] TypeScriptのカスタムグローバルインターフェース(.d.tsファイル)を設定する方法は?

2022-05-14 19:29:42

質問

現在、Webpack2とTypeScriptを使用するReactJSのプロジェクトに取り組んでいます。1つのことを除いて、すべてが完璧に動作します - 私は自分自身で書いたインターフェイスを別のファイルに移動する方法を見つけることができず、それらはアプリケーション全体から見えるようになります。

プロトタイプの目的のために、私は最初にそれらを使用するファイルで定義されたインターフェイスを持っていましたが、最終的に私は複数のクラスで必要とされるものを追加し始め、すべての問題はそこから始まりました。どんな変更をしても tsconfig.json にどんな変更を加えても、ファイルをどこに置いても、IDE と Webpack の両方が、名前 ( "Could not find name 'IMyInterface'" ).

以下は、私の現在の tsconfig.json ファイルです。

{
  "compilerOptions": {
    "baseUrl": "src",
    "outDir": "build/dist",
    "module": "commonjs",
    "target": "es5",
    "lib": [
      "es6",
      "dom"
    ],
    "typeRoots": [
      "./node_modules/@types",
      "./typings"
    ],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": false,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ],
  "types": [
    "typePatches"
  ]
}

見ての通り、私の tsconfig.json はプロジェクトディレクトリのルートにあり、すべてのソースは ./src にあり、私はカスタム .d.ts ファイルを ./typings の中に入れて、それを typeRoots .

TypeScript 2.1.6と2.2.0でテストしましたが、どちらも動きません。

すべてうまくいくようにする一つの方法は、私の typings ディレクトリを src というディレクトリを作成し、次に import {IMyInterface} from 'typings/blah' を追加することができますが、これは私が使う必要のあるものではないので、私には正しいとは思えません。私は、これらのインターフェイスが、私のアプリケーション全体で「魔法のように」利用可能であってほしいのです。

以下はサンプルです。 app.d.ts ファイルのサンプルです。

interface IAppStateProps {}
interface IAppDispatchProps {}
interface IAppProps extends IAppStateProps, IAppDispatchProps {}

必要なのは export あるいは declare ? 名前空間でラップする必要がなければいいのですが......。

アップデート(2020年10月)

この質問がまだ驚くほど人気があるのを見て、私は解決策をより詳細に説明したいと思いました。

まず、人々を混乱させる可能性があり、また混乱させるべきことは、私の質問の最後にあげたインターフェースの例には、実際には、どんな export キーワードがないことです。あってもなくても変わらないと思って質問には入れなかったのだと思います。まあ、そんなことはないことが判明しており export キーワードは、単にインターフェイスを使うことができるか、それとも明示的に import を明示する必要があります。

というわけで、TypeScriptでの動作は以下のようになります。

もし、消費モジュールでインポートすることなく、単純に使用できるインターフェースや型が必要な場合、そのインターフェースは .ts あるいは、理想的には .d.ts ファイル インポートやエクスポートが同じファイルに存在することなく . なぜなら、同じファイルから少なくとも 1 つのものをエクスポートするとすぐに、それはモジュールになり、そのモジュールにあるすべてのものは、その後消費者によってインポートされなければならないからです。

という型を持ちたいとします。 Dictionary という型があり、インポートせずに使えるようにしたいとします。それを宣言する方法は次のようになります。

// types.d.ts
interface Dictionary {}
interface Foo {}
interface Bar {}

使い方は、単純に

// consumer.ts
const dict: Dictionary = {};

しかし、何らかの理由で のいずれかになります。 がエクスポートされた場合、動作しなくなります。

// types.d.ts
interface Dictionary {}
interface Foo {}
export interface Bar {}

また、そのファイルにimportがある場合は動作しません。

// types.d.ts
import { OtherType } from 'other-library';

interface Dictionary {}
interface Foo extends OtherType {}
interface Bar {}

もしそうだとすると、唯一の方法は Dictionary を使用する唯一の方法は、それをエクスポートしてコンシューマでインポートすることでしょう。

// types.d.ts
export interface Dictionary {}
interface Foo {}
export interface Bar {}

// consumer.ts
import { Dictionary } from './types';

const dict: Dictionary = {};

--isolatedModules

を使用する際に、さらに気をつけなければならない点があります。 isolatedModules モジュールフラグは、重要なことに、Create React App - を使用するとデフォルトで有効になります (無効にすることはできません)。 .ts ファイルでは、少なくとも1つのものをエクスポートしなければなりません。 "All files must be modules when the '--isolatedModules' flag is provided.".このフラグが指定されている場合、すべてのファイルはモジュールでなければなりません。 というエラーが発生します。つまり Dictionary インターフェイスを types.ts ファイルからエクスポートされたものでなければなりません。それは .ts ファイルからのエクスポートでなければなりません。 .d.ts ファイルに書き出されます。

// types.d.ts
interface Dictionary {}        // works
export interface Dictionary {} // works

// types.ts
interface Dictionary {}        // doesn't work with --isolatedModules enabled
export interface Dictionary {} // works


N.B.

アンビエントモジュールについては、@dtabuenc さんの回答にもあるように( .d.ts ファイル)は不愉快なので、私の訂正はアドバイスとして受け取られるべきではありません。あくまでTypeScriptで通常のモジュールとアンビエントモジュールがどのように動作するかを説明するための試みです。

どのように解決するのか?

魔法のように利用可能なインターフェイスやグローバルな型は非常に推奨されず、ほとんどがレガシーに任されるべきです。 また、アンビエント宣言ファイル (例: ) を使用するべきではありません。 d.ts ファイル) を使うべきではありません。これらは、外部の非typescriptコードの代わりになるものです (本質的には、typescriptの型をjsコードに埋めて、javascriptとよりよく統合できるようにするものです)。

あなたが書くコードには、プレーンな .ts ファイルを使って、 インターフェースや型を定義する必要があります。

グローバル型は推奨されませんが、あなたの問題に対する答えは、2つのタイプの .ts ファイルです。これらは scriptsmodules .

の中にあるものはすべて script にあるものはすべてグローバルになります。つまり、スクリプトでインターフェースを定義すれば、 アプリケーション全体を通してグローバルに利用できるようになります (スクリプトがコンパイル時に ///<reference path=""> タグか files:[] または includes:[] またはデフォルトの **/*.ts の中に tsconfig.json .

もう一つのファイルタイプは 'モジュール' で、何でも module にあるものはすべてそのモジュールの私的なものです。モジュールから何かをエクスポートした場合、他のモジュールがそれをインポートすることを選択すれば、他のモジュールも利用できるようになります。

何が .ts ファイルをスクリプトやモジュールと呼ぶのでしょうか?そうですね......もしあなたが import/export を使用している場合、そのファイルはモジュールになります。もし import/export ステートメントがない場合、それはグローバルスクリプトになります。

私の推測では、あなたはうっかりと import または export を宣言してモジュール化すると、そのモジュール内ですべてのインターフェイスがprivateになります。もしグローバルにしたいのであれば、ファイル内でimport/exportステートメントを使用していないことを確認する必要があります。