Skip to content

noImportCycles

¥Summary

¥How to configure

biome.json
{
"linter": {
"rules": {
"nursery": {
"noImportCycles": "error"
}
}
}
}

¥Description

防止循环导入。

¥Prevent import cycles.

当一个文件直接或间接地导入另一个文件,而该文件又再次导入了原始文件时,此规则会发出警告。

¥This rule warns when a file imports another file that, either directly or indirectly, imports the original file again.

循环引用可能导致出现意外的 undefined 符号,这通常被认为是不良的代码习惯。

¥Cycles can lead to symbols that are unexpectedly undefined and are generally considered poor code hygiene.

如果检测到循环引用,建议移动代码,使导入语句单向传递,即不要将 “back” 指向导入文件。

¥If a cycle is detected, it is advised to move code such that imports only go in a single direction, i.e. they don’t point “back” to the importing file.

但是,允许导入自身文件,并且该规则不会针对这些用例触发。这允许将函数/变量封装到命名空间中,而不是使用静态类(触发 noStaticOnlyClass)。

¥However, files that import themselves are allowed, and the rule won’t trigger for these use cases. This allows for encapsulation of functions/variables into a namespace instead of using a static class (triggers noStaticOnlyClass).

¥Examples

¥Invalid

foobar.js
import { baz } from "./baz.js";
export function foo() {
baz();
}
export function bar() {
console.log("foobar");
}
/foobar.js:1:21 lint/nursery/noImportCycles ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

This import is part of a cycle.

> 1 │ import { baz } from “./baz.js”;
^^^^^^^^^^
2 │
3 │ export function foo() {

This import resolves to /baz.js
… which imports /foobar.js
… which is the file we’re importing from.

baz.js
import { bar } from "./foobar.js";
export function baz() {
bar();
}
/baz.js:1:21 lint/nursery/noImportCycles ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

This import is part of a cycle.

> 1 │ import { bar } from “./foobar.js”;
^^^^^^^^^^^^^
2 │
3 │ export function baz() {

This import resolves to /foobar.js
… which imports /baz.js
… which is the file we’re importing from.

¥Valid

foo.js
import { baz } from "./baz.js";
export function foo() {
baz();
}
bar.js
export function bar() {
console.log("foobar");
}
baz.js
import { bar } from "./bar.js";
export function baz() {
bar();
}
foobaz.js
export function foo() {
console.log("foobaz");
}
export * as baz from './foobaz.js';
import { baz } from './foobaz.js';
types.ts
import type { bar } from "./qux.ts";
export type Foo = {
bar: typeof bar;
};
qux.ts
import type { Foo } from "./types.ts";
export function bar(foo: Foo) {
console.log(foo);
}

¥Options

该规则提供了如下所述的选项。

¥The rule provides the options described below.

在发现循环导入时,忽略仅类型导入。编译器会移除仅类型导入 (import type),从而在运行时减少一个导入循环。请注意,命名类型导入 (import { type Foo }) 不被视为仅类型导入,因为如果启用了 verbatimModuleSyntax 选项,编译器不会将其移除。默认启用。

¥Ignores type-only imports when finding an import cycle. A type-only import (import type) will be removed by the compiler, so it cuts an import cycle at runtime. Note that named type imports (import { type Foo }) aren’t considered as type-only because it’s not removed by the compiler if the verbatimModuleSyntax option is enabled. Enabled by default.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noImportCycles": {
"options": {
"ignoreTypes": false
}
}
}
}
}
}

¥Invalid

types.ts
import type { bar } from "./qux.ts";
export type Foo = {
bar: typeof bar;
};
qux.ts
import type { Foo } from "./types.ts";
export function bar(foo: Foo) {
console.log(foo);
}
/qux.ts:1:26 lint/nursery/noImportCycles ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

This import is part of a cycle.

> 1 │ import type { Foo } from “./types.ts”;
^^^^^^^^^^^^
2 │
3 │ export function bar(foo: Foo) {

This import resolves to /types.ts
… which imports /qux.ts
… which is the file we’re importing from.

¥Related links