TypeScript Decorators and Circular Dependencies

后端 未结 3 441
小蘑菇
小蘑菇 2021-01-06 19:03

Consider the sample of inter-dependent code (below) that makes use of decorators.

Now consider the following workflow (yes, I do want to pass the actual exported cla

相关标签:
3条回答
  • 2021-01-06 19:20

    If you can postpone actions performed in decorator - you can overcome the limitation and break circular dependency. From the names of your real decorators @HasMany and @BelongsTo it looks like you are attaching some sort of the metadata to each class for the later usage - if so here is my suggestion:

    1. Extend your @Test decorator signature

    export function Test(passedClass: Function | string)

    I assume here that the decorator will store meta information in some sort of static dictionary, like: . Where properties can look like

    {
        hasMany: {new(): any} | string
        belongsTo: {new(): any} | string
    }
    
    1. Inside decorator create new properties object with hasMany/belongsTo properties set to passedClass. If passedClass is not string - check all already added properties and replace any hasMany/belongsTo that are of string type and equal current passedClass.name

    2. Remove reference to Child from Parent.

    This is somewhat naive implementation and you can implement some private fields instead to hide the intermediate string data and keep away from exposing union type fields.

    Hope this will help you.

    0 讨论(0)
  • 2021-01-06 19:31

    How about doing the same, but structuring your code differently?
    If both Child and Parent reside in the same file then it shouldn't be a problem.

    That might not sound optimal as it's comfortable to separate code to modules due to length and logic, but that can be solved in a way.
    You can have a main file that has base classes for those, even abstract:

    // Base.ts
    import {Test} from "./Decorators";
    
    @Test(BaseChild)
    export abstract class BaseParent {}
    
    @Test(BaseParent)
    export abstract class BaseChild {}
    

    And then in your specific modules:

    // Parent.ts
    import {BaseParent} from "./Base";
    
    export class Parent extends BaseParent {}
    

    And

    // Child.ts
    import {BaseChild} from "./Base";
    
    export class Child extends BaseChild {}
    
    0 讨论(0)
  • 2021-01-06 19:37

    Hit the same problem today. I solved it slightly differently, by replacing @Test(Parent) by @Test(() => Parent).

    Instead of tracking the class constructor (Parent) in metadata, I track the thunk that returns the constructor (() => Parent). This delays the evaluation of the Parent imported variable until the thunk is invoked, which does the trick.

    0 讨论(0)
提交回复
热议问题