Skip to content

Return type of inherited methods breaks function chaining #275

Closed
@teamdandelion

Description

@teamdandelion

Suppose I want to make a class with tons of chainable methods, like setters. This works fine.

class Chainable {
  public set1(arg) {
    this.arg1 = arg;
    return this;
  } 

  public set2(arg) {
    this.arg2 = arg;
    return this;
  }

  public set3(arg) {
    this.arg3 = arg;
    return this;
  }
}

This allows us to create and setup a new Chainable much more concisely than would otherwise be possible.

a = new Chainable().set1(foo).set2(bar).set3(baz);
// vs
a = new Chainable();
a.set1(foo);
a.set2(bar);
a.set3(baz);

The problem occurs when we want to extend our Chainable class and maintain the chainability of the function calls.

class SuperChainable extends Chainable {
  public set4(arg) {
    this.arg4 = arg;
    return this;
  }

  public set5(arg) {
    this.arg5 = arg;
    return this;
  }

  public set6(arg) {
    this.arg6 = arg;
    return this;
  }
}
a = new SuperChainable().set4(foo).set1(baz); 
// this is fine, because set4 returns a SuperChainable 

a = new SuperChainable().set1(baz).set4(foo);
// this breaks, because set1 is returning a Chainable, not SuperChainable

var a: SuperChainable;
a = new SuperChainable.set1(baz); // typeError, set1 returns a Chainable, not SuperChainable

There is a workaround, but it is verbose and boiler-platey:

class SuperChainable extends Chainable {
  public set4(arg) {
    this.arg4 = arg;
    return this;
  }

  public set5(arg) {
    this.arg5 = arg;
    return this;
  }

  public set6(arg) {
    this.arg6 = arg;
    return this;
  }

  public set1(arg) {
    super.set1(arg);
    return this;
  }

  public set2(arg) {
    super.set2(arg);
    return this;
  }

  public set3(arg) {
    super.set3(arg);
    return this;
  }
}

When set1 is called on a SuperChainable and returns this, the this really is a SuperChainable and not a Chainable. So it seems to me that the typescript compiler is in error in treating the return value as a Chainable. If this error were fixed, it would be much easier to create inherited objects that support method chaining.

(copied over from now-closed issue on codeplex: https://typescript.codeplex.com/workitem/2332)

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already createdNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions