Home > Software design >  Angular typescript gives reference error when implementing subclasses to abstract class
Angular typescript gives reference error when implementing subclasses to abstract class

Time:09-16

I get the current error:

Uncaught ReferenceError: can't access lexical declaration 'AbstractClass' before initialization

when doing this in a new Angular project:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  title = '';
  
  ngOnInit() {
    console.log(JSON.stringify(new (AbstractClass.get("MyId1"))()))
  }
}

And I can not see why this would happen since I first reference a static method, then instantiates the class reference that function returnes and then call a function on the newly initilized class...

AbstractClass.ts

export abstract class AbstractClass {
    abstract getModelName(): string;

    public static get(id: string): Type<AbstractClass> {
        switch (id) {
            case "MyId1":
                return MyId1ImplementationClass;
            case "MyId2":
                return MyId2ImplementationClass;
            default:
                return MyId1ImplementationClass;
        }
    }
}

MyId1ImplementationClass.ts

export class MyId1ImplementationClass extends AbstractClass {
    getModelName(): string {
        return "Id1!";
    }
}

MyId2ImplementationClass.ts

export class MyId2ImplementationClass extends AbstractClass {
    getModelName(): string {
        return "Id2!";
    }
}

CodePudding user response:

You have a circular dependency here that is almost certainly the cause of the error. Your implementation classes depend on the abstract class but the abstract class also depends directly on the implementations.

The fix the problem you have to break the circular dependency. One common way is to use a registry. This is a pattern in which the implementations add themselves to a map or list, which the static function can then access.

Something like:

export abstract class AbstractClass {
    abstract getModelName(): string;

    protected static registry = new Map<string, Type<AbstractClass>>()

    public static register () {
        this.registry.set(this.prototype.getModelName.call(null), this as any)
    }

    public static get(id: string): Type<AbstractClass> {
        return this.registry.get(id)
    }
}
export class MyId1ImplementationClass extends AbstractClass {
    getModelName(): string {
        return "Id1!";
    }
}

MyId1ImplementationClass.register()
  • Related