typescript - Ciclu de dependență detectat. eslint cu typeorm


Am două entități TypeORM cu relație unu-la-unu bidirecțională:

Departament:

@Entity('Departament')
export default class Departament {
  @PrimaryGeneratedColumn()
  id: string;

  @Column()
  departament_name: string;

  @OneToOne(type => User, user => user.departament)
  @JoinColumn()
  user: User;

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  UpdatedAt: Date;
}

Utilizator:

@Entity('User')
export default class User {
  @PrimaryGeneratedColumn()
  id: string;

  @Column()
  name: string;

  @Column()
  last_name: string;

  @Column()
  email: string;

  @Column()
  login: string;

  @Column()
  password: string;

  @OneToOne(type => Departament, departament => departament.user)
  departament: Departament;
}

și acestea sunt setările mele .eslintrc:

{
  "env": {
    "es6": true,
    "node": true,
    "jest": true
  },
  "extends": [
    "airbnb-base",
    "plugin:@typescript-eslint/recommended",
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended"
  ],
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly"
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint", "prettier"],
  "rules": {
    "prettier/prettier": "error",
    "no-new": "off",
    "no-underscore-dangle": "off",
    "class-methods-use-this": "off",
    "no-await-in-loop": "off",
    "import/prefer-default-export": "off",
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "ts": "never"
      }
    ],
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": ["**/*.spec.ts", "src/utils/tests/*.ts"]
      }
    ],
    "no-useless-constructor": "off",
    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        "argsIgnorePattern": "_"
      }
    ],
    "@typescript-eslint/no-useless-constructor": "error",
    "camelcase": "off",
    "@typescript-eslint/camelcase": "off"
  },
  "overrides": [
    {
      "files": ["*.js"],
      "rules": {
        "@typescript-eslint/no-var-requires": "off"
      }
    }
  ],
  "settings": {
    "import/extensions": [".ts", ".js"],
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".js"]
    },
    "import/resolver": {
      "typescript": {
        "alwaysTryTypes": true
      }
    }
  }
}

am primit aceste erori:

ciclu de dependență detectat.eslintimport/no-cycle

pe (utilizator și departament)

și :

'type' este definit, dar niciodată folosit. Argumentele neutilizate permise trebuie să se potrivească cu /_/u.eslint@typescript-eslint/no-unused-vars

Nu pot să rezolv asta și nu știu care este cea mai bună opțiune de făcut, urmez ghidul de început al TypeORM

Răspuns #1

Anumite cazuri de importuri circulare pot fi confuze pentru compilator, dar de cele mai multe ori ele pot fi rezolvate fără probleme. Regula eslint import/no-cycle există pentru a elimina eventualele probleme din timp, ceea ce este un lucru bun. Există un răspuns excelent pe Stack Overflow care oferă mai multe informații despre această problemă și sugerează evitarea dependențelor circulare în totalitate.

Există o discuție în repo-ul TypeORM care oferă multiple soluții, fiecare având propriile compromisuri. Cele mai complete soluții sunt schemele de entități și referințele sub formă de șiruri de caractere. Ambele soluții folosesc o idee similară - să definească relația printr-un șir de caractere și să rezolve șirul mai târziu.

Aceasta este o metodă comună de rezolvare a dependențelor circulare care poate fi întâlnită și în alte ORM-uri, cum ar fi SQLAlchemy din Python sau ActiveRecord din Ruby on Rails. Ideea este simplă: clasa/șablonul entității este preluat dintr-un registru prin șirul de caractere al numelui entității, ceea ce elimină necesitatea de a importa explicit module pentru a defini relația.

Permiteți-mi să dau un exemplu pentru ambele.

Scheme de entitate

Aceasta este o metodă funcțională de a defini entitățile tale. Definiția clasei este înlocuită cu o instanță de EntitySchema, și nu sunt folosiți decoratorii.

export const DepartmentEntity = new EntitySchema({
  name: "Department",
  columns: { /* omitting for brevity */ },
  relations: {
    user: {
      type: "one-to-one",
      target: "User"
    }
  }
})
export const UserEntity = new EntitySchema({
  name: "User",
  columns: { /* omitting for brevity */ },
  relations: {
    department: {
      type: "one-to-one",
      target: "Department"
    }
  }
})

Referințe la șiruri

Aceasta este o schimbare mai puțin radicală față de ceea ce ai deja, ar necesita doar modificarea funcțiilor de tip și a funcțiilor de pe partea inversă în șiruri de caractere. Pentru a tipa corect atributul de relație, ar trebui să folosești import type:

import type User from './user';

@Entity('Department')
export default class Department {
  // omitting most of the columns
  // ...

  @OneToOne('User', 'department')
  @JoinColumn()
  user: User;
}
import type Department from './department';

@Entity('User')
export default class User {
  // omitting most of the columns
  // ...

  @OneToOne('Department', 'user')
  department: Department;
}

Ce să aleg?

Depinde de tine. Mecanica este exact aceeași, dar schemele de entitate sunt susceptibile să rămână și să devină cetățeni de primă clasă în versiunile viitoare TypeORM și îți oferă mai multă siguranță de tip decât pot oferi clasele.