0.1.0 • Published 7 years ago

tslint-circular-dependencies v0.1.0

Weekly downloads
1,601
License
MIT
Repository
github
Last release
7 years ago

tslint rules to work around circular dependencies

This package contains four rules, including fixes, to work around some of the issues that arise with circular imports:

  • imports-after-export
  • initialize-statics-after-imports
  • new-instance-after-imports
  • no-instanceof-operator

Usage

Install

npm install -D tslint-circular-dependencies

This will install the rules and set up your tslint.json file.

TypeScript 2.4.1 These rules have been tested with TypeScript 2.4.1. If you're seeing no output when you run these rules, try updating TypeScript to this version.

Run

tslint [path] --fix

Manually configuring tslint.json (optional)

This package will install itself into your tslint.json as follows:

  "extends" : [
    ...
    "tslint-circular-dependencies"
    ...
  ]

Keep the rule names intact. tslint does not document a certain execution order for rules, but right now they are executed in alphabetic order. It is important that the rules in this package are executed in a particular order, and thats 1. imports-after-export, 2. initialize-statics-after-imports, 3. new-instance-after-imports.

Inside the Rules

imports-after-export

Moves all import statements – except those that are used as superclasses in an extends clause – after the last export statement.

Why

Circular imports work if the import occurs after export.

The following code will fail:

// a.ts
import { B } from './b';

export class A {
  constructor() {
    this.b = new B();
  }
}
// b.ts
import { A } from './a';

export class B {
  constructor() {
    this.a = new A();
  }
}

This fails because at the time the import is executed, module.exports is still undefined.

StepStatementa.exportsb.exports
1import { B } from './b';undefinedundefined
2import { A } from './a';undefinedundefined
3export class B {...}undefinedclass B
4export class A {...}class Aclass B

The following code will work:

// a.ts
export class A {
  constructor() {
    this.b = new B();
  }
}

import { B } from './b';
// b.ts
export class B {
  constructor() {
    this.a = new A();
  }
}

import { A } from './a';
Stepstatementa.exportsb.exports
1export class A {...}class Aundefined
2import { B } from './b';class Aundefined
3export class B {...}class Aclass B
4import { A } from './a';class Aclass B

initialize-statics-after-imports

This rule

  • encapsulates non-primitive static initializers in a static function
  • executes that static function after all import statements

Improvement Suggestion

  • Only move initializers that reference imported symbols. This rule currently encapsulates all static initializers into a function. This could be more accurately move only those static initializers that reference imported symbols. Keep in mind this may mean you'd have to analyze the execution path in case of initializers like this:
class A {
  public static x = A.initializeX();

  private static initializeX() {
    return new X(); // this will fail because X isn't imported yet
  }
}

import { X } from 'X';

new-instance-after-imports

This rule moves new expressions to after the last import statement to make sure all dependencies have been loaded.

class A {
  ...
}

new A(); // will be moved to after `import` statement

import { B } from 'B';

no-instanceof-operator

This rule changes any use of the instanceof operator with a constructor.name comparison, e.g.

Original code before this rule:

class A {}
let a = new A();
a instanceof A;

Original code after this rule:

class A {}
let a = new A();
a.constructor.name === 'A';

Related Projects

tslint-no-circular-imports - TSLint plugin to detect and warn about circular imports

dependency-cruiser – Validate and visualize dependencies. With your rules. JavaScript. TypeScript. CoffeeScript. ES6, CommonJS, AMD.

0.1.0

7 years ago

0.0.14

7 years ago

0.0.13

7 years ago

0.0.12

7 years ago

0.0.11

7 years ago

0.0.10

7 years ago

0.0.9

7 years ago

0.0.8

7 years ago

0.0.7

7 years ago

0.0.6

7 years ago

0.0.5

7 years ago

0.0.4

7 years ago

0.0.3

7 years ago

0.0.2

7 years ago

0.0.1

7 years ago