jnsmalm
jnsmalm

Reputation: 348

Using `import type` statement to fix circular dependency reference error

Let's say I have two files, A.js and B.js. Both need references to each other like this.

A.js

import { B } from "b"

export class A {
  constructor(public name: string) {}
}

let b = new B();
b.print(new A("This is a random name"));

B.js

import { A } from "a"

export class B {
  print(a: A) {
    console.log(a.name);
  }
}

The example above will create a circular reference which currently does not work in the JavaScript runtime I'm using. The file B.js really only need the type information, not the actual export object). I want the type from A.js to get static type checking. Is this possible?

Upvotes: 25

Views: 16832

Answers (4)

artem
artem

Reputation: 51769

NOTE: This answer is outdated. The "import elision" feature described here was removed in TypeScript 4.9. Other, newer answers show better ways of doing type-only imports like import type {A} from 'a' or type A = import('a').A

You don't need to do anything special to import only type information from module a.

Typescript will do it for you - if the only thing module `b` needs form `a` is type information, compiled file `b.js` will not have `require("./a")` statement, that is, it will not have runtime dependency on `a`. Quote from [typescript handbook](http://www.typescriptlang.org/docs/handbook/modules.html#optional-module-loading-and-other-advanced-loading-scenarios):

> The compiler detects whether each module is used in the emitted
> JavaScript. If a module identifier is only ever used as part of a type
> annotations and never as an expression, then no require call is
> emitted for that module.

Most likely, the example code you posted in your question is incomplete, and real b module has runtime dependency on a - find out where it is and get rid of that, and you won't have this problem.

Upvotes: 26

Noah Stahl
Noah Stahl

Reputation: 7623

As of TypeScript 3.8, use import type:

import type { SomeThing } from "./some-module.js";

export type { SomeThing };

Reference:

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-exports

Upvotes: 16

Chris Groh
Chris Groh

Reputation: 320

This is now directly possible in TypeScript 2.9.

type MyType = import('mymodule').MyType;
const myValue: import('mymodule').MyType;

Upvotes: 30

drewwyatt
drewwyatt

Reputation: 6027

You used the [typescript] tag here, so I am going to assume you are using typescript.

Make this a 1-way street. Kill off the circular dependency. I would probably move this into 1 file, but you can still split it up like this.

a.ts (just an interface)

export interface A {
    name: string;
    new (name: string);
}

b.ts (implementation)

import { A } from 'a';

export class B implements A {
    /*...*/
}

Upvotes: -3

Related Questions