web-dev-qa-db-ja.com

定義ファイル(* d.ts)のインポートクラス

Express Storageのタイピングを拡張して、セッションストレージでカスタムデータを使用できるようにします。クラスUserのインスタンスであるオブジェクトreq.session.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ファイルを作成して、定義を既存のエクスプレスセッションタイピングとマージしました。

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ファイルで独自のクラスを使用するにはどうすればよいですか?

編集:コンパイル時に定義ファイルを生成するように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;
    }
}

しかし、ステートメントを一番上にインポートすると、まだ機能しません。何か案は?

42
Michał Lytek

2年間のTypeScript開発の後、私はついにこの問題を解決することができました。

基本的に、TypeScriptには、「ローカル」(通常のモジュール)とアンビエント(グローバル)の2種類のモジュールタイプ宣言があります。 2番目の種類では、既存のモジュール宣言とマージされるグローバルモジュール宣言を記述できます。このファイルの違いは何ですか?

_d.ts_ファイルは、インポートがない場合にのみ、アンビエントモジュール宣言として扱われます。インポート行を指定した場合、グローバル行ではなく通常のモジュールファイルとして扱われるようになったため、モジュール定義の拡張は機能しません。

そのため、ここで説明したすべてのソリューションが機能しないのです。しかし幸いなことに、TS 2.9以降では、import()構文を使用して、型をグローバルモジュール宣言にインポートできます。

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

したがって、この行import("./user").User;は魔法をかけ、すべてが機能するようになりました:)

89
Michał Lytek

[〜#〜] update [〜#〜]

TypeScript 2.9以降、タイプをグローバルモジュールにインポートできるようになりました。詳細については、受け入れられた回答を参照してください。

元の回答

あなたが直面している問題は、モジュール宣言の拡張それからクラスタイピングに関するものだと思います。

これをコンパイルしようとするとわかるように、エクスポートは問題ありません。

// app.ts  
import { User } from '../models/user'
let theUser = new User('theLogin', 'thePassword')

Expressのモジュール宣言を補強しようとしているようで、本当に近いです。これはトリックを行う必要があります:

// index.d.ts
import { User } from "./models/user";
declare module 'express' {
  interface Session {
    user: User;
    uuid: string;
  }
}

ただし、このコードの正確さは、当然、エクスプレス宣言ファイルの元の実装に依存します。

3
Pelle Jacobs

express-sessionのロジックに従うだけでは不可能ですか?

own.d.ts

import express = require('express');
import { User } from "../models/user";

declare global {
    namespace Express {
        interface Session {
            user: User;
            uuid: string;
        }
    }
}

メインのindex.ts

import express from 'express';
import session from 'express-session';
import own from './types/own';

const app = express();
app.get('/', (req, res) => {
    let username = req!.session!.user.login;
});

少なくともこれは問題なくコンパイルできるようです。完全なコードについては、 https://github.com/masa67/so39040108 を参照してください

0
masa