2

Suppose I have a class with internal private properties:

export class foo {
    private bar_:string;
    private baz_:number;
    constructor() { }

I know that I can get the values from bar and baz by writing a getter for the variable.

    get bar():string {
        return this.bar_;
    }
    get baz():number {
        return this.baz_;
    }

This then allows me to access data using:

let A:foo = new foo();
console.log(foo.baz);

Is there a way to have a simple generic getter, so when working with a more structured class, I could access any field without needing to write an individual get.

console.log(A.field2);

The field2 is not a defined getter, but I would like to be able to do something like the following in the class:

export class foo {
    private bar_:string;
    private baz_:number;
    private field2_:string;
    constructor() { }

    get X():any {        // X here is some placeholder that could be used, which contains the field name being asked (bar_, baz_, etc.)
        return this.X;       // This would assume that a field is the same name as what was passed.
    }

On the HTML or other area, I could access the value as A.bar_ which would allow me to protect the private variable, but get external access to it without the need to write a getter for each field. This could then be extended to more complex structures as well.

0

1 Answer 1

9

If you want the properties to be read only and you can just set them in the constructor, you could use the readonly modifier:

export class foo {
    constructor(
        public readonly bar:string,
        public readonly baz:number,
        public readonly field2:string) { 

    }
}

If you only want to access the property from HTML templates, you could use a decorator to create getters, but they will not be present on the type:

function createGetter (target: any, key: string) {
    let propName = key.substr(0, key.length - 1);
    Object.defineProperty(target, propName, {
        get: function() {
            return this[key]
        }
    });
}


export class foo {
    @createGetter private bar_:string;
    @createGetter private baz_:number = 10;
    @createGetter private field2_:string;
    constructor() { }
}

If you don't mind a bit of convoluted syntax and just declaring the properties, you coulda access the from typescript as well:

function withGetters<TProps>() {
    return <TBase>(cls: new () => TBase) : new () => TProps & TBase => {
        return <any>cls;
    };
}
class baseFoo {
    @createGetter private bar_:string;
    @createGetter private baz_:number = 10;
    @createGetter private field2_:string;
    constructor()  { }
}
export const foo = withGetters<{ 
    readonly bar: string;
    readonly baz: number; 
    readonly field2: string; 
}>()(baseFoo);
Sign up to request clarification or add additional context in comments.

2 Comments

Impressive. But why let propName = key.substr(0, key.length - 1);?
@jcairney that was just the convention used in the question, the fields end in _ and the properties have the _ removed. Took me a while to remember, this was a while back :)

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.