परिभाषा फ़ाइल में आयात वर्ग (* d.ts)


104

मैं सत्र भंडारण में अपने कस्टम डेटा का उपयोग करने की अनुमति देने के लिए एक्सप्रेस सत्र टंकण का विस्तार करना चाहता हूं। मेरे पास एक वस्तु है 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;
    }
}

लेकिन यह बिल्कुल काम नहीं कर रहा है - वीएस कोड और tsc इसे नहीं देखते हैं। इसलिए मैंने सरल प्रकार के साथ परीक्षण की परिभाषा बनाई:

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

और परीक्षण क्षेत्र ठीक काम कर रहा है, इसलिए आयात समस्या का कारण है।

मैंने /// <reference path='models/user.ts'/>इसके बजाय आयात को जोड़ने की कोशिश की, लेकिन tsc ने उपयोगकर्ता वर्ग को नहीं देखा - मैं * d.ts फ़ाइल में अपनी कक्षा का उपयोग कैसे कर सकता हूँ?

संपादित करें: मैंने कंपाइल पर परिभाषा फ़ाइल बनाने के लिए tsc निर्धारित किया है और अब मेरे पास मेरे user.d.ts हैं:

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

और एक्सप्रेस सेशन के विस्तार के लिए स्वयं की टाइपिंग फ़ाइल:

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

लेकिन अभी भी काम नहीं कर रहा है जब शीर्ष पर आयात बयान। कोई विचार?

जवाबों:


293

टाइपस्क्रिप्ट विकास के दो साल बाद, मैं आखिरकार इस समस्या को हल करने में कामयाब रहा हूं।

असल में, टाइपस्क्रिप्ट में दो प्रकार के मॉड्यूल प्रकार की घोषणा है: "स्थानीय" (सामान्य मॉड्यूल) और परिवेश (वैश्विक)। दूसरा प्रकार वैश्विक मॉड्यूल घोषणा लिखने की अनुमति देता है जो मौजूदा मॉड्यूल घोषणा के साथ विलय कर रहे हैं। इस फ़ाइलों के बीच अंतर क्या हैं?

d.tsफ़ाइलों को एक परिवेशी मॉड्यूल घोषणाओं के रूप में माना जाता है, यदि उनके पास कोई आयात नहीं है। यदि आप एक आयात लाइन प्रदान करते हैं, तो इसे अब सामान्य मॉड्यूल फ़ाइल के रूप में माना जाता है, न कि वैश्विक एक के रूप में, इसलिए मॉड्यूल परिभाषाओं को बढ़ाने से काम नहीं होता है।

इसीलिए हमने यहाँ जिन सभी समाधानों पर चर्चा की है वे काम नहीं करते हैं लेकिन सौभाग्य से, टीएस 2.9 के बाद से हम import()सिंटैक्स का उपयोग करके वैश्विक मॉड्यूल घोषणा में प्रकारों को आयात करने में सक्षम हैं :

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

तो लाइन import("./user").User;जादू करता है और अब सब कुछ काम करता है :)


4
यह इसे करने का सही तरीका है, कम से कम टाइपस्क्रिप्ट के हाल के संस्करणों के साथ
जेफरसन टावारेस

1
यह दृष्टिकोण आदर्श समाधान है जब वैश्विक मॉड्यूल जैसे कि नोड की processवस्तु का विस्तार करने वाले इंटरफेस की घोषणा करते हैं ।
टेफिन एलिस

2
धन्यवाद, यह एक्सप्रेस मिडलवेयर के साथ मेरे मुद्दों को ठीक करने का एकमात्र स्पष्ट उत्तर था!
काट्सुके

2
धन्यवाद @ Michał Lytek मुझे आश्चर्य है कि इस दृष्टिकोण के लिए कोई आधिकारिक प्रलेखन संदर्भ है?
Gena


5

अपडेट करें

टाइपस्क्रिप्ट 2.9 के बाद से, आप वैश्विक मॉड्यूल में प्रकार आयात करने में सक्षम प्रतीत होते हैं। अधिक जानकारी के लिए स्वीकृत उत्तर देखें।

मूल ANSWER

मुझे लगता है कि आप जिस समस्या का सामना कर रहे हैं वह मॉड्यूल घोषणाओं को बढ़ाने के बारे में है और फिर वर्ग टाइपिंग है।

निर्यात ठीक है, जैसा कि आप नोटिस करेंगे यदि आप इसे संकलित करने का प्रयास करते हैं:

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

हालाँकि, इस कोड की शुद्धता एक्सप्रेस घोषणा फ़ाइल के मूल कार्यान्वयन पर निश्चित रूप से निर्भर करती है।


यदि मैं आयात कथन को अंदर ले जाता हूं तो मुझे त्रुटि मिलती है Import declarations in a namespace cannot reference a module.:। मैं अपने कोड कॉपी-पेस्ट, तो मुझे मिल गया: Import or export declaration in an ambient module declaration cannot reference module through relative module name.। और अगर मैं गैर-सापेक्ष पथ का उपयोग करने की कोशिश करता हूं तो मैं अपनी फ़ाइल का पता नहीं लगा सकता हूं, इसलिए मैंने घोषणा फ़ोल्डर को नोड_मॉडल पर ऐड ऐड पथ "declarations/models/user"पर स्थानांतरित कर दिया, लेकिन अभी भी संपूर्ण डी। एसटी काम नहीं कर रहा है - इंटेलिजेंस में एक्सप्रेस सत्र का अपना विस्तार नहीं देख सकता है या tsc।
मिचेल लाइटेक

मैं इन त्रुटियों से परिचित नहीं हूँ, क्षमा करें। शायद आपके सेटअप में कुछ अलग है? क्या यह आपके लिए संकलन है? gist.github.com/pellejacobs/498c997ebb8679ea90826177cf8a9bad
पेले जैकब्स

इस तरह से यह काम करता है लेकिन फिर भी असली ऐप में काम नहीं करता है। मेरे पास सत्र वस्तु के साथ एक एक्सप्रेस अनुरोध वस्तु है और यह अन्य प्रकार की घोषित है - नेमस्पेस एक्सप्रेस में नहीं मॉड्यूल 'एक्सप्रेस': github.com/DefinitelyTyped/DefinitelyTyped/blob/master/ ...
मिचेल लाइटेक

5
यह मेरे लिए भी काम नहीं करता है। एक बार जब मैं अपनी tsd.d.ts फ़ाइल में आयात विवरण जोड़ देता हूं, तो पूरी फ़ाइल काम करना बंद कर देती है। (मैं उस फ़ाइल में परिभाषित चीजों के लिए अपने आवेदन के बाकी हिस्सों में त्रुटियां प्राप्त करता हूं।)
वेरन जेन्सेन

5
मुझे भी यही समस्या थी। यह काम करता है अगर आप अपने .d.ts के भीतर एक घोषित मॉड्यूल में आयात का उपयोग करते हैं: declare module 'myModule' {import { FancyClass } from 'fancyModule'; export class MyClass extends FancyClass {} }
ज़ंडर करें

4

माइकेल Lytek से जवाब के लिए धन्यवाद । यहाँ एक और तरीका है जो मैंने अपने प्रोजेक्ट में इस्तेमाल किया है।

हम इसे हर जगह लिखने के बिना कई बार आयात Userऔर पुन: उपयोग कर सकते हैं import("./user").User, और यहां तक कि इसे विस्तारित या फिर से निर्यात भी कर सकते हैं।

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

मज़े करो :)


0

क्या केवल तर्क का पालन करना संभव नहीं है 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 देखें


1
आपको घोषणा फ़ाइलों को आयात नहीं करना चाहिए, क्योंकि tscउन्हें संकलित नहीं किया जाएगा। वे संकलन में होने के लिए हैं, लेकिन आउटपुट में नहीं हैं
बालिंट सेसक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.