Home > Software engineering >  How to approach this method chaining in TypeScript? Error ts(2339)
How to approach this method chaining in TypeScript? Error ts(2339)

Time:04-07

I'm receiving a ts(2339) error in attempting to use method chaining on flexible methods that can be used to both get and set a private properties.

Suppose I have the following class:

export default class A {

  private _propertyA!: number;
  private _propertyB!: string;

  constructor() {
    this._propertyA;
    this._propertyB;
    this._init();
  }

  private _init() {
    // Do something in initializing the class.
  };

  public getPropertyA() {
    return this._propertyA;
  }

  public getPropertyB() {
    return this._propertyB;
  }

  public propertyA(value?: number): number | this {
    if (value === undefined) return this.getPropertyA();
    this.setPropertyA(value);
    return this;
  }

  public propertyB(value?: string): string | this {
    if (value === undefined) return this.getPropertyB();
    this.setPropertyB(value);
    return this;
  }

  public setPropertyA(value: number): this {
    this._propertyA = value;
    return this;
  }

  public setPropertyB(value: string): this {
    this._propertyB = value;
    return this;
  }

}

I have "getters" via get prefix on methods and "setters" via set prefix on methods. Then there are "shorthand" methods that are flexible that can either get or set a private property depending on whether or not an argument is provided to the method.

When I attempt to use the following method chaining, it results in a TypeScript error (see code comments):

import A from './a';

// Results in the following TypeScript error:
const a = new A()
  .propertyA(100)
  .propertyB('value');
// Property 'propertyB' does not exist on type 'number | A'.
// Property 'propertyB' does not exist on type 'number'.ts(2339)

// Results in the following TypeScript error:
const a = new A()
  .propertyB('value')
  .propertyA(100);
// Property 'propertyA' does not exist on type 'string | A'.
// Property 'propertyA' does not exist on type 'string'.ts(2339)

// This works but we are not chaining.
const a = new A()
  .propertyA(100);

// Works as expected.
const a = new A()
  .setPropertyA(100)
  .setPropertyB('value');

TypeScript Version 4.6.3

It seems to me that TypesSript is not recognizing the return type is this when there is no argument provided to these methods and the value parameter is undefined. And the error is introduced in method chaining.

Is there a bug that I'm overlooking or how can this be adjusted to make these shorthand methods work?

Many thanks!

CodePudding user response:

Use overloads:

  public propertyA(): number;
  public propertyA(value: number): this;
  public propertyA(value?: number): number | this {
    if (value === undefined) return this.getPropertyA();
    this.setPropertyA(value);
    return this;
  }

Then when you call without parameters it returns a number, and if you provide a value it's this:

new A().propertyA(); // number

new A()
  .propertyA(100)
  .propertyB("foo") // assuming you did the same for propertyB
  • Related