1. ホーム
  2. typescript

[解決済み] 定義ファイル(*d.ts)にクラスをインポートする。

2022-05-03 13:13:51

質問内容

Express Session の型付けを拡張して、セッションストレージでカスタムデータを使用できるようにしたいと思います。私は、オブジェクト req.session.user のインスタンスで、私のクラス User :

export class User {
    public login: string;
    public hashedPassword: string;

    constructor(login?: string, password?: string) {
        this.login = login || "" ;
        this.hashedPassword = password ? UserHelper.hashPassword(password) : "";
    }
}

を作成しました。 own.d.ts ファイルを作成し、既存のExpressセッションの型付けに定義をマージします。

import { User } from "./models/user";

declare module Express {
    export interface Session {
        user: User;
    }
}

しかし、これは全く機能しません。VS Codeとtscはそれを見ません。そこで、単純な型を使ってテスト定義を作成しました。

declare module Express {
    export interface Session {
        test: string;
    }
}

そして、テストフィールドは問題なく動作しているので、インポートが問題を引き起こしています。

また /// <reference path='models/user.ts'/> しかし、tscはUserクラスを見ませんでした。どうすれば、*d.tsファイルで独自のクラスを使用できますか?

EDIT コンパイル時に定義ファイルを生成するようにtscを設定し、user.d.tsが出来上がりました。

export declare class User {
    login: string;
    hashedPassword: string;
    constructor();
    constructor(login: string, password: string);
}

そして、Express Sesionを拡張するための独自のタイピングファイルです。

import { User } from "./models/user";
declare module Express {
    export interface Session {
        user: User;
        uuid: string;
    }
}

しかし、まだ上にimport文があると動作しません。何かアイデアはありますか?

どうすればいいですか?

TypeScriptの開発を始めて2年、ようやくこの問題を解決することができました。

基本的にTypeScriptには、local"(通常のモジュール)とambient(グローバル)の2種類のモジュールタイプの宣言があります。2つ目のタイプは、既存のモジュール宣言にマージされるグローバルなモジュール宣言を記述することができる。この2つのファイルの違いは何でしょうか?

d.ts ファイルは、インポートを持たない場合のみ、アンビエントモジュール宣言として扱われます。import 行を与えると、グローバルなものではなく、通常のモジュールファイルとして扱われるようになり、モジュール定義の補強はうまくいきません。

だから、ここで説明した解決策はすべてうまくいかないわけです。しかし幸いなことに、TS 2.9以降では、グローバルモジュール宣言に import() の構文があります。

declare namespace Express {
  interface Request {
    user: import("./user").User;
  }
}

ということは、この行は import("./user").User; を実行すると、すべてがうまくいくようになりました :)