Класс импорта в файле определения (* d.ts)

Я хочу расширить типичные выражения 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, чтобы объединить определение с существующими типом экспресс-сессии:

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;
    }
}

Но все еще не работает, когда оператор импорта сверху. Любые идеи?

Ответ 1

После двух лет разработки TypeScript мне наконец удалось решить эту проблему.

По сути, TypeScript имеет два вида объявления типов модулей: "локальный" (обычные модули) и окружающий (глобальный). Второй вид позволяет писать декларации глобальных модулей, которые объединяются с декларацией существующих модулей. Каковы различия между этими файлами?

Файлы d.ts обрабатываются как объявления окружающего модуля, только если они не импортируются. Если вы предоставляете строку импорта, она теперь обрабатывается как обычный файл модуля, а не как глобальный, поэтому расширение определений модулей не работает.

Поэтому все решения, которые мы обсуждали здесь, не работают. Но, к счастью, начиная с TS 2.9 мы можем импортировать типы в объявление глобальных модулей, используя синтаксис import():

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

Итак, линия import("./user").User; делает волшебство, и теперь все работает :)

Ответ 2

ОБНОВИТЬ

Начиная с машинописного текста 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

Разве нельзя просто следовать логике с помощью 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.