5

The following code should print 'Hello World!' on the screen. Insead it prints Error: Cannot read property 'id' of undefined. Why?

abstract class Parent {
  constructor() {
    console.log(this.getData());
  }

  abstract getData(): string;
}

class Child extends Parent {
  constructor(private item: any) {
    super();
  }

  getData(): string {
    return this.item.id;
  }
}

new Child({id: 'Hello World!'});

Here is a working example.

1 Answer 1

5

The problem is that the call to getData within the Parent constructor happens before the assignment of the parameter item to the private field item. That's because the automatic initialization happens after the super() call, not before it. See *** comments:

abstract class Parent {
  constructor() {
    console.log(this.getData());  // *** Calls Child's getData
  }

  abstract getData(): string;
}

class Child extends Parent {
  constructor(private item: any) {
    super();                       // *** Calls Parent's constructor
    // ** Automatic initialization happens here, *after* the `super()` call
  }

  getData(): string {
    return this.item.id;           // *** So here, `this.item` is `undefined`
  }
}

new Child({id: 'Hello World!'});

This is one of the reasons calling methods from constructors is generally not best practice: They can be overridden by child classes, but the child class's initialization may not be complete (as in your case).

Sign up to request clarification or add additional context in comments.

8 Comments

Do you have a solution for this problem? For now I'm wrappring getData() call in setTimeout, but it doesn't look good.
@Humberd - The usual solution is to not call getData from the constructor (unsatisfying as that sounds :-) ). Instead, leave it for the subclass to do (ideally, not in its constructor either).
You can rename the constructor as init() and then call super.init() in the child constructor. I tested it and it works
@CristianTraìna - Best not to put it in the child constructor, either, unless it's a final class, and even then it's a bit dodgy... It needs to be a post-construction step. I shouldn't have said "...for the subclass to do..." above. Really, it's for the code using the class to do, after construction.
@T.J.Crowder I meant calling before super() then super.init(), what can be wrong with this?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.