HagelslagPakje
HagelslagPakje

Reputation: 414

How to cross import TypeScript classes?

Im trying to rewrite JavaScript code to TypeScript, but I'm running into some problems when trying to import a class into a different TypeScript file.

This used to be done with jQuery Namespaces, where it worked fine.

My situation is:

file Layouts:

import { Commands } from './funnel.commands'
var commands = new Commands(); /*<--- problematic line*/

export class Layouts {

    loadHtmlSubLayout(done: Function, layoutname: string): void {
    /*...*/
        commands.CloseSubLayout();
    /*...*/
    };

    closeSubLayout(layoutContent): void {
    /*...*/
    };


}

file Commands:

import { Layouts } from './funnel.layouts'
var layouts = new Layouts();

export class Commands {

    GotoLayout(el, cmd: CommandObj): void {
       /*...*/
        layouts.loadSpecificLayout(layouts.onLayoutSwitched, layoutName);
    };
    CloseSubLayout(): void {
    /*...*/
        if ($subLayoutContent.length !== 0) {
          layouts.closeSubLayout($subLayoutContent);
        }
    };
}

Whenever I try to run this, I get the error 'Commands is not a constructor'. How can I make sure this works without having to move the methods around?

Upvotes: 1

Views: 2049

Answers (1)

hackape
hackape

Reputation: 19947

One of these 2 module has to back-off and use async/lazy init the other in order to break the circular import chain.

In your example, I assume Commands is used ahead of Layouts. So you can do the following:

file funnel.commands

import { Layouts } from './funnel.layouts'
var layouts = new Layouts

export class Commands {
  CloseSubLayout(): void {
    layouts.closeSubLayout({});
  };
}

file funnel.layouts

import { Commands } from './funnel.commands'
var commands: Commands
setTimeout(() => {
  commands = new Commands()
})

export class Layouts {
  loadHtmlSubLayout(): void {
    commands.CloseSubLayout();
  };

  closeSubLayout(layoutContent): void {
    console.log('You just called Layouts.closeSubLayout()')
  };
}

other party:

import { Commands } from './funnel.commands'

var commands = new Commands()

commands.CloseSubLayout()

Above solution should work, but circular dependency is still an anti-pattern. Since you're rewriting a codebase, better refactor that part. I suggest use some sort of dependency injection pattern.

file dependencies

export const dependencies: any = {
  _register(map: any) {
    Object.assign(this, map)
  }
}

file funnel.commands

import { dependencies as dep } from './dependencies'

export class Commands {
  CloseSubLayout(): void {
    dep.layouts.closeSubLayout({});
  };
}

file index

import { Commands } from './funnel.commands'
import { Layouts } from './funnel.layouts'
import { dependencies } from './dependencies'

var commands = new Commands()
var layouts = new Layouts()
dependencies._register({ commands, layouts })

Upvotes: 2

Related Questions