टाइपस्क्रिप्ट - डेकोरेटर पर परिपत्र निर्भरता

Sep 18 2020

मुझे अपने डेकोरेटर्स पर सर्कुलर डिपेंडेंसी मिलती है क्योंकि मेरी क्लास ThingAका रिलेशन ThingBऔर इसके विपरीत है। मैंने इस मुद्दे के बारे में कई प्रश्न पढ़े हैं:

  • जावास्क्रिप्ट / टाइपस्क्रिप्ट में परिपत्र निर्भरता समस्या के लिए सुंदर तय

  • टाइपस्क्रिप्ट डेकोरेटर और परिपत्र निर्भरता

लेकिन मैं अपने मामले के लिए एक वैध समाधान खोजने में सक्षम नहीं था। मैंने कोशिश की के रूप में कई लोगों से परिवर्तन करने के लिए सुझाव @hasOne(ThingA)के लिए @hasOne(() => ThingA)एक आलसी लोड हो रहा है मजबूर और निर्भरता को तोड़ने के लिए है, लेकिन क्योंकि मैं निर्माता नाम प्राप्त करने में सक्षम नहीं कर रहा हूँ इस समाधान काम नहीं करता है। मुझे कंस्ट्रक्टर थिंगब के मेटाडेटा में इसे जोड़ने के लिए कंस्ट्रक्टर (उदाहरण: 'थिंगा') का नाम चाहिए।

मेरे मूल कोड (आलसी लोड संशोधन के बिना)

thinga

@hasAtLeast(0, ThingB)
export class ThingA extends RTContent {
    @IsEmail()
    email: string;
}

ThingB

@hasOne(ThingA)
export class ThingB extends RTContent {
    @IsString()
    description: string;
}

सज्जाकार:

export type LinkConstraint<C extends RTContent> = {
    content: string; // name of the constructor (ex. 'ThingA')
    maxOccurrences: number;
    minOccurrences: number;
    constructor: { new(...args: any[]): C };
}

function constraintFactory<C extends RTContent>(minOccurrences: number, maxOccurrences: number, associated: { new(...args: any[]): C }) {
    return (constructor: Function) => {
        const constraints = Reflect.getMetadata('linkConstraints', constructor) || [];
        const constraint: LinkConstraint<C> = {
            content: associated?.name,
            minOccurrences,
            maxOccurrences,
            constructor: associated
        };
        constraints.push(constraint);
        Reflect.defineMetadata('linkConstraints', constraints, constructor)
    }
}

export function hasOne<C extends RTContent>(associated: { new(...args: any[]): C }) {
    return constraintFactory(1, 1, associated)
}

export function hasAtLeast<C extends RTContent>(minOccurrences: number, associated: { new(...args: any[]): C }) {
    return constraintFactory(minOccurrences, Infinity, associated)
}

जवाब

2 hackape Sep 26 2020 at 14:26

मैं देखता हूं कि आपका डेकोरेटर वास्तव में कंस्ट्रक्टर को संशोधित नहीं करता है, यह केवल कुछ मेटाडेटा प्रविष्टि को जोड़ने के लिए कुछ साइड-इफ़ेक्ट कोड चलाता है। इस प्रकार @decoratorवाक्यविन्यास जरूरी नहीं है।

मेरी सलाह है कि आप न तो सजाएँ और न ThingAही ThingB, उन्हें निर्यात करें-जैसा है। आप सजावट को किसी अन्य मॉड्यूल में स्थगित कर देते हैं, जो दोनों का सामान्य अभिभावक होना चाहिए ThingAऔर ThingB। इस तरह परिपत्र निर्भरता हल हो गई है।

उदाहरण के लिए, './things/index.ts'आप में है:

import { ThingA } from './things/ThingA';
import { ThingB } from './things/ThingB';

hasOne(ThingA)(ThingB);
hasAtLeast(0, ThingB)(ThingA);

export { ThingA, ThingB }

अब आपके कोड का अन्य हिस्सा './things/index.ts'सीधे आयात कर सकता है , बजाय सीधे से './things/ThingA(or B).ts'। यह सुनिश्चित करेगा कि कक्षाओं की तात्कालिकता से पहले सजावट को निष्पादित किया जाता है।


यदि आपको डेकोरेटर का उपयोग करना चाहिए, तो आलसी लोड आपका सबसे अच्छा दांव है। @hasOne(() => ThingA)चाल करना चाहिए, लेकिन आपको hasOneतदनुसार, थोड़ा हैक के कार्यान्वयन को संशोधित करने की आवश्यकता है ।

function hasOne(target) {
  if (typeof target === "function") {
    setTimeout(() => {
      _workOnTarget(target())
    }, 0)
  } else {
    _workOnTarget(target)
  }
}

कुंजी चर मूल्य तक पहुँचने में देरी करना है।

इस हैक को काम करने के लिए, हम अभी भी इस तथ्य पर भरोसा करते हैं कि ये सज्जाकार केवल साइड-इफेक्ट हैं, कंस्ट्रक्टर को संशोधित न करें। तो यह परिपत्र निर्भरता समस्या का एक सामान्य समाधान नहीं है। अधिक सामान्य पैटर्न बंद आलसी मूल्यांकन है। अधिक जटिल हालांकि, अगर आपको वास्तव में आवश्यकता है, तो pls टिप्पणियों में पूछें।

आपके मामले के लिए, इसके बाद के संस्करण को काम करना चाहिए। लेकिन आपको ThingAकिसी भी मॉड्यूल के शीर्ष स्तर के अंदर तुरंत या बी सही नहीं होना चाहिए , क्यूज जो setTimeoutकॉलबैक से पहले होगा , इस प्रकार हैक को तोड़ देगा।