'Force a client to call a specific method

How do I force a client to call the build method at the end of the command chain?

const foo = new Foo();
foo.bar().a() // I want to make sure that the `build` method was called.

Here's my example:

interface IFoo {
    bar(): IBar;
    build(): string;
}

class Foo {
    public commands;

    constructor() {
        this.commands = []
    }

    public bar(): any {
        return new Bar(this);
    }

    public build(): any {
        return this.commands.join(' ')
    }

}

interface IBar {
    a(): IFoo
}

class Bar {
    private foo: Foo;

    constructor(foo){
        this.foo = foo;
    }

    public a(): IFoo {
        this.foo.commands.push('something')
        return
    }
}



Solution 1:[1]

Like Peter said, just structure your API such that it provides no utility to a consumer except in the ways you desire:

TS Playground

class Base {
  protected commands: string[];

  constructor (commands?: string[]) {
    this.commands = commands ?? [];
  }

  public build (): string {
    return this.commands.join(' ');
  }

  private toString (): string {
    return this.build();
  }

  private toJSON (): string[] {
    return this.commands;
  }
}

class Foo extends Base {
  public bar (): Bar {
    return new Bar(this.commands);
  }
}

class Bar extends Base {
  public a (): Foo {
    this.commands.push('something');
    return new Foo(this.commands);
  }
}


// Use:

const foo = new Foo();
const bar = foo.bar();
const anotherFoo = foo.bar().a();
const command = anotherFoo.build();

anotherFoo.commands; /*
           ^^^^^^^^
Property 'commands' is protected and only accessible within class 'Base' and its subclasses.(2445) */

console.log(command); // "something"
console.log(JSON.stringify(anotherFoo)); // '["something"]'
console.log(String(anotherFoo)); // "something"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jsejcksn