3

Assume a simple class like so:

class Simple {
  private _transactions: [];
  makeTransaction() { ... }
  revertTransaction() { ... }
  // some other methods as well...
}

let obj = new Simple();
obj.makeTransaction(...);
obj.makeTransaction(...);
obj.revertTransaction(...);

Now, I want to expose some more methods related to reporting and I would like to group them like so:

obj.reports.allTransactions();
obj.reports.reveretedTransactions();
obj.reports.clearedTransactions();

These methods will be using the private variables within the Simple class itself to return some reports.

I have used the following to achieve this:

class Simple {
  private _test = () => { return this._transaction }
  reports = {
    getAll: this._test
  }
}

This works, but it has a couple of downsides:

  1. It forces me to declare all required functions as part of the class itself and then reference them in the reports object again.
  2. Typescript shows me that obj.reports.getAll is a property, although I can invoke it as a function too. Even so, I don't get the correct function signature hint.
  3. It forces me to use arrow functions (closures) needlessly.

Is there a better way of doing the same?

1 Answer 1

2

You can create a class for the reports object:

class Reports {
    private _transactions: any[];

    constructor(transactions: any[]) {
        this._transactions = transactions;
    }

    getAll() {
        return this._transactions;
    }
}

class Simple {
    private _transactions: any[];
    public reports: Reports;

    constructor() {
        this._transactions = [];
        this.reports = new Reports(this._transactions);
    }

    makeTransaction() {}
    revertTransaction() { }
}

(code in playground)


Edit

You can also expose reports as a type:

interface Reports {
    getAll(): any[];
}

class Simple {
    private _transactions: any[];
    public reports: Reports;

    constructor() {
        this._transactions = [];
        this.reports = {
            getAll: () => {
                return this._transactions;
            }
        }
    }

    makeTransaction() {}
    revertTransaction() { }
}

(code in playground)


2nd Edit

Another option is to seperate the reports into a different class but to have the Simple instance as its member with all members of the instance as public.
If you then turn Simple into an interface you can hide those public members:

class Reports {
    private _simple: SimpleImpl;

    constructor(simple: SimpleImpl) {
        this._simple = simple;
    }

    getAll() {
        return this._simple.transactions;
    }
}

interface Simple {
    makeTransaction();
    revertTransaction();
}

class SimpleImpl implements Simple {
    public transactions: any[];
    public reports: Reports;

    constructor() {
        this.transactions = [];
        this.reports = new Reports(this);
    }

    makeTransaction() {}
    revertTransaction() {}
}

(code in playground)

If only Reports class and the Simple interface are exposed then the public members are only visible to the instances of Reports.

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

3 Comments

Hmm.. Though this does work, it splits implementation between two classes.. The example I gave was a stripped down one.. In my actual use-case, I have about 10 private fields and their reference is not constant (clear() => this._list = []).. But if there is no other way to go.. Ill accept this answer.. =)
You can also expose reports as a type.. THIS! is what i needed! thanks a lot mate.. this worked just fine.. no need for separate classes sharing data.. and the closure maintains the this reference.. awesome!
If this class gets too big and/or the logic in Reports gets too long then it's probably better to separate it into a different class (avoiding "bad smells"). I updated my answer with a nice way of doing that.

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.