1

I am trying to create an abstract class ParseContent that allows it's implementors to implement a parse method, the catch is that the ParseContent abstract class has other methods, that return instances of the inheriting class. is this possible?

export abstract class ParseContent extends RawContent { 
  parsed: any

  constructor(params: ConstructorParameters<typeof RawContent>[0] & {
    parsed: any
  }) {
    super(params)
    this.parsed = params.parsed
  }

  abstract parse<T> (content: string): T

  static fromString(opt: Parameters<typeof RawContent['fromString']>[0]) { 
    const pureOpts = super.fromStringOpts(opt)
    const parsed = this.parse(pureOpts.content)
    return new this({ ...pureOpts, parsed })
  }

  static async fromPath(opt: Parameters<typeof RawContent['fromPath']>[0]) { 
    const pureOpts = await super.fromPathOpts(opt)
    const parsed = this.parse(pureOpts.content)
    return new this({ ...pureOpts, parsed })
  }

}

export class JSONContent extends ParseContent { 
  static parse(content: string): any { 
    return JSON.parse(content)
  }
}
2
  • Is what possible? "that the ParseContent abstract class has other methods, that return instances of the inheriting class" << this? Commented Apr 27, 2020 at 19:52
  • With a little bit of refactor, you could create an abstract method, for example createOne, and implement in your child classes, so you can replace return new this(...) by return this.createOne(). This could also help when you have an specific class with a completely different behaviour and attributes initialization. Commented Apr 27, 2020 at 20:07

1 Answer 1

1

Because you're using new this in your static members, they'll create instances of whatever class they're called on. For instance, calls to JSONContent.fromPath(...) (JSONContent inherits it from ParseContent, since ParseContent is the prototype of JSONContent — a feature fairly specific to JavaScript and TypeScript) will create a JSONContent instance, because during the call to fromPath, this is JSONContent. It will use the parse on JSONContent for the same reason: this is JSONContent.

Example:

class Parent {
    static wrapper() {
        return this.create();
    }
    static create() {
        const ctor = (this && this[Symbol.species]) || this;
        return new ctor();
    }
}

class Child extends Parent {
}
console.log(Child.create() instanceof Child);  // true
console.log(Child.wrapper() instanceof Child); // true

You can give subclasses the ability to override that with the species pattern (and probably others), but my sense of what you're asking is that you want the default behavior.

As for the TypeScript aspect of this, I'm afraid the news may not be good.

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

Comments

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.