打字稿外部模块可以有循环依赖吗?

时间:2014-04-24 20:43:39

标签: module typescript

看起来这是不允许的。 requireJS在以下内容上抛出错误(this post与内部模块解决不同):

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

运行properties.ts:

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

export class RunProperties extends element.Element implements IRunProperties {
}

2 个答案:

答案 0 :(得分:24)

不,模块不能具有循环依赖关系,除非它们在同一个文件中。每个文件都是按顺序,同步处理的,因此当它转到第二个文件时,完整的文件定义(包括所有导出)都没有完成,第二个文件立即尝试要求/引用第一个文件,并且等等。

通常,您可以通过将接口或基类引入公共定义文件(仅基本上是接口)并让其他文件将其用作公共接口来打破循环依赖关系。而不是直接引用类。这是许多平台中的典型模式。

答案 1 :(得分:2)

我有同样的问题,我能够通过创建工厂类来修复它,该工厂类允许注册子类并使用Generics进行实例化。

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

请参阅以下示例代码:

基类(abstract.control.ts)

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

父类(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));
        }
    }
}

我不再需要导入子类,因为我使用factory.ts来实例化子类。

工厂类(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);
    } 
}

虽然似乎在c: { new ({}): T }调用了类构造函数,但它实际上并没有调用它。但是通过new运算符获取对构造函数的引用。在我的情况下,构造函数的参数{}是必需的,因为基类AbstractControl需要它。

(1)儿童班(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)儿童班(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;