Pregunta

It looks like this is not allowed. requireJS is throwing an error on the following (this post is different as it was resolved with internal modules):

element.ts:

import runProperties = require('./run-properties');
export class Element {
   public static factory (element : IElement) : Element {

        switch (element.type) {
            case TYPE.RUN_PROPERTIES :
                return new runProperties.RunProperties().deserialize(<runProperties.IRunProperties>element);
        }
        return null;
    }
}

run-properties.ts:

import element = require('./element');

export class RunProperties extends element.Element implements IRunProperties {
}
¿Fue útil?

Solución

No, modules can't have circular dependencies unless they are in the same file. Each file is being processed in sequence, synchronously, so the full file definition (including all of the exports for example) hasn't been completed when it goes to second file, which immediately tries to require/reference the first file, and so on.

Normally, you can break a circular dependency by introducing an interface or base class into a common definition file(s) (basically interfaces only) and having the other files use that as a common "interface" rather than directly referencing the classes. This is a typical pattern in many platforms.

Otros consejos

I have same issue, I was able to fix it by creating factory class that allows registration of child classes and used Generics for instantiation.

Reference: https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics

See sample code below:

Base Class (abstract.control.ts)

export type AbstracControlOptions = {
    key?:string;
}
export abstract class AbstractControl {
    key:string;
    constructor(options:AbstracControlOptions){
        this.key = options.key;
    }    
}

Parent Class (container.ts)

import { AbstractControl, AbstracControlOptions } from './abstract.control';
import { Factory } from './factory';

export { AbstracControlOptions };
export abstract class Container extends AbstractControl {
    children: AbstractControl[] = [];
    constructor(options: AbstracControlOptions) {
        super(options);
    }
    addChild(options: { type: string }) {
        var Control:any = Factory.ControlMap[options.type];
        if (Control) {
            this.children.push(Factory.create(Control, options));
        }
    }
}

I don't have to import the child classes any more, because I'm using factory.ts to instantiate the child classes.

Factory Class(factory.ts)

import {AbstractControl, AbstracControlOptions} from './abstract.control';

type ControlMap<T extends AbstractControl> = {
    [type:string]:T
};

export class Factory{
    static ControlMap: ControlMap<any> = {};
    static create<T extends AbstractControl>(c: { new ({}): T; }, options: AbstracControlOptions): T {
        return new c(options);
    } 
}

Although class constructor seems to be called at c: { new ({}): T } but it does not actually calls it. But gets the reference to the constructor via new operator. The parameter {} to the constructor in my case is required because the base class AbstractControl requires it.

(1) Child Class(layout.ts)

import { Factory } from './factory';
import { Container, AbstracControlOptions } from './container';

export type LayoutlOptions = AbstracControlOptions & {
    type:"layout";
}
export class Layout extends Container {
    type: string = "layout";
    constructor(options:LayoutlOptions) {
        super(options);
    }
}
Factory.ControlMap["layout"] = Layout;

(2) Child Class(repeater.ts)

import { Factory } from './factory'
import { Container, AbstracControlOptions } from './container';

export type RepeaterOptions = AbstracControlOptions & {
    type: "repeater";
}
export class Repeater extends Container {
    type: string = "repeater";
    constructor(options:RepeaterOptions) {
        super(options);
    }
}
Factory.ControlMap["repeater"] = Repeater;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top