Sınıfı tanım dosyasında içe aktar (* d.ts)


96

Özel verilerimin oturum depolamasında kullanılmasına izin vermek için Ekspres Oturum tiplerini genişletmek istiyorum. Bir nesne var req.session.userbenim sınıfının bir örneğidir User:

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

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

Bu yüzden own.d.tstanımı mevcut ekspres oturum tipleriyle birleştirmek için dosyamı oluşturdum:

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

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

Ama hiç çalışmıyor - VS Code ve tsc bunu görmüyor. Bu yüzden basit tipte test tanımı oluşturdum:

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

Ve test alanı sorunsuz çalışıyor, bu yüzden içe aktarma sorunu neden oluyor.

Bunun /// <reference path='models/user.ts'/>yerine içe aktarmayı da eklemeyi denedim, ancak tsc Kullanıcı sınıfını görmedi - * d.ts dosyasında kendi sınıfımı nasıl kullanabilirim?

DÜZENLEME: tsc'yi derleme sırasında tanım dosyaları oluşturacak şekilde ayarladım ve şimdi benim user.d.ts'im var:

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

Ve Express Sesion'u genişletmek için kendi yazma dosyası:

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

Ama yine de ithalat beyanı üstte çalışırken çalışmıyor. Herhangi bir fikir?

Yanıtlar:


271

İki yıllık TypeScript geliştirmeden sonra, sonunda bu sorunu çözmeyi başardım.

Temel olarak, TypeScript iki tür modül türü bildirimine sahiptir: "yerel" (normal modüller) ve ortam (genel). İkinci tür, mevcut modül bildirimi ile birleştirilen genel modül bildiriminin yazılmasına izin verir. Bu dosyalar arasındaki farklar nelerdir?

d.tsdosyalar, yalnızca içe aktarımları yoksa ortam modülü bildirimleri olarak değerlendirilir. Bir içe aktarma satırı sağlarsanız, artık global değil, normal bir modül dosyası olarak değerlendirilir, dolayısıyla modül tanımlarını genişletmek çalışmaz.

İşte bu yüzden burada tartıştığımız tüm çözümler işe yaramıyor. Ancak neyse ki, TS 2.9'dan beri, import()sözdizimini kullanarak türleri global modül bildirimine aktarabiliyoruz :

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

Yani çizgi import("./user").User;sihir yapıyor ve şimdi her şey çalışıyor :)


4
Bunu yapmanın doğru yolu, en azından daktilo yazısının son sürümlerinde
Jefferson Tavares

1
Bu yaklaşım, Node'un processnesnesi gibi global modülleri genişleten arayüzleri bildirirken ideal çözümdür .
Teffen Ellis

1
Teşekkürler, bu, Express Middleware genişletmeyle ilgili sorunlarımı düzeltmenin tek net cevabıydı!
Katsuke

Thx, çok yardımcı oldu. Mevcut bir projede bunu yapmanın başka yolu yoktu. Bunu, İstek sınıfını genişletmek yerine tercih edin. Dziękuję bardzo.
Christophe Geers

1
Teşekkür ederim @ Michał Lytek Bu yaklaşım için herhangi bir resmi belge referansı var mı merak ediyorum?
Gena

3

GÜNCELLEME

TypeScript 2.9'dan bu yana, türleri genel modüllere aktarabiliyorsunuz. Daha fazla bilgi için kabul edilen cevaba bakın.

ORİJİNAL CEVAP

Bence karşılaştığınız sorun, modül bildirimlerini artırmaktan daha çok sınıf yazmayla ilgili.

Bunu derlemeye çalışırsanız fark edeceğiniz gibi dışa aktarmada sorun yok:

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

Görünüşe göre modül bildirimini artırmaya çalışıyorsunuz Expressve gerçekten yakınsınız. Bu hile yapmalı:

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

Bununla birlikte, bu kodun doğruluğu elbette ekspres beyan dosyasının orijinal uygulamasına bağlıdır.


Ben import ifadesini taşırsanız hatası alıyorum içeride: Import declarations in a namespace cannot reference a module.. Ben kodunuzu yapıştırın kopya halinde aldım: Import or export declaration in an ambient module declaration cannot reference module through relative module name.. Ve göreli olmayan yolu kullanmaya çalışırsam dosyamı bulamıyorum, bu yüzden bildirimler klasörünü node_modules ad add yoluna taşıdım "declarations/models/user"ama yine de tüm d.ts çalışmıyor - intelisense'de ekspres oturumun kendi uzantısını göremiyorum veya tsc.
Michal Lytek

Bu hatalara aşina değilim, üzgünüm. Belki kurulumunuzda farklı bir şey vardır? Bu sizin için derlemek için mi? gist.github.com/pellejacobs/498c997ebb8679ea90826177cf8a9bad .
Pelle Jacobs

Bu şekilde çalışır, ancak yine de gerçek uygulamada çalışmaz. Orada oturum nesnesi olan bir ekspres istek nesnem
Michał Lytek

5
Benim için de çalışmıyor. Tsd.d.ts dosyama içe aktarma ifadelerini ekledikten sonra, tüm dosya çalışmayı durduruyor. (Başvurumun geri kalanında bu dosyada tanımlanan şeyler için hatalar alıyorum.)
Vern Jensen

5
Ben de aynı sorunu yaşadım. İçe aktarımı .d.ts içinde beyan edilen bir modülde kullanırsanız çalışır:declare module 'myModule' {import { FancyClass } from 'fancyModule'; export class MyClass extends FancyClass {} }
13'te zunder

2

Sayesinde Michał Lytek gelen cevap . İşte projemde kullandığım başka bir yöntem.

Her yere yazmadan birden çok kez içe aktarabilir Userve yeniden kullanabilir import("./user").User, hatta genişletebilir veya yeniden dışa aktarabiliriz .

declare namespace Express {
  import("./user");  // Don't delete this line.
  import { User } from "./user";

  export interface Request {
    user: User;
    target: User;
    friend: User;
  }

  export class SuperUser extends User {
    superPower: string;
  }

  export { User as ExpressUser }
}

İyi eğlenceler :)


-1

Sadece mantığı takip etmek mümkün değil mi express-session:

own.d.ts:

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

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

Esas olarak 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;
});

En azından bu herhangi bir sorun olmadan derleniyor gibi görünüyor. Kodun tamamı için bkz. Https://github.com/masa67/so39040108


1
Beyanname dosyalarını içe aktarmamalısınız çünkü tsconları derlemez. Derlemede olmaları gerekiyor ancak çıktıda değiller
Balint Csak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.