parchii
parchii

Reputation: 11

Sharing private members in composition

Say I have two classes:

class Element {
    parent: Manager;
    get() {
        this.parent.table();
    }
}
class Manager {
    run(){}
    table(){}
}

However, say that this is a library, run() is the only method of Manager that should be exposed. If a user runs table(), disaster ensues. We could make table() private,

export class Manager {
    run(){}
    private table(){}
}

But this obviously causes a problem with Element trying to call table(). How should this be organized?

I've been told that it is common practice to prefix an underscore on this kind of thing to indicate no touchy, like

export class Manager {
    run(){}
    _table(){}
}

And this works! Though I was curious if there was a stronger alternative.

I've also considered using a function instead of methods, ie

function table(manager: Manager) {}

export class Manager {
    run(){}
}

Though this makes other Manager private members impossible to use in table().

Upvotes: 0

Views: 101

Answers (2)

Craig  Hicks
Craig Hicks

Reputation: 2558

Instead of exporting classes, you can export interfaces in library defintion file for the users, like this:

import {manager} from "manager"
export interface Manager {
    run(){}
}
export const manager: Manager;

Now the users cannot call 'table'.

Upvotes: 0

Edgar P-Yan
Edgar P-Yan

Reputation: 319

Use the index property notation to get the private members of the class. It is intentionally made by the TypeScript team as a workaround for edge-cases where you don't have any other choice but to access the private members. It'll be quite easy to read, doesn't require additional code, and looks simple:

class Element {
    parent: Manager;
    get() {
        const res = this.parent['table']();
        res satisfies string; // It also correctly resolves all the typings
    }
}

class Manager {
    private table(): string{
        return ''
    }
}

A little sidenote: it's still better to design the code so that the two separate classes will not need to interact with each other through private methods, because classes are supposed to be separate and standalone "living creatures", it also makes unit and integration testing a lot harder. And besides that, in the future, with the adoption of EcmaScript Private Class Fields these kinds of workarounds will be impossible.

Upvotes: 0

Related Questions