Typescript: When using the native method 'defineProperty ' to define a 'Getter' for a class, the compiler error!

Created on 14 Mar 2017  ·  4Comments  ·  Source: microsoft/TypeScript

TypeScript Version: 1.8.0

Code:

// a function used to define targetObject's descriptor from SourceObject's properties

function defineGetter(SourceObject, targetObject) {

    Object.keys(SourceObject).forEach(function (key) {
        Object.defineProperty(targetObject.prototype, key, {
            get: function () {
                return SourceObject[key]
            },
            enumerable: true,
            configurable: true
        })
    })
}

interface IForm {
    name: string;
    label: string;
    value: any;
    sequence: number;
    width: number;
    type: number;
}


class Form {
    constructor(form: IForm) {
        defineGetter(form, Form);
    }
    get info() {
        return `name is ${this.name}, label is ${this.label}`;
    }
}

let form = new Form({
       name: '1',
       label: '2',
       value: 3,
       sequence: 4,
       width: 5,
       type: 6
})

Expected behavior & Actual behavior:
I want to complete my definition of Getter with metadata(a Singleton Object) through a defineGetter () method, It seems to be successful. but, When I manually define another Getter (info), the compiler prompts:

“ error TS2339: Property 'name' does not exist on type 'Form'”
“ error TS2339: Property 'type' does not exist on type 'Form'. ”

I just want to use a function to solve my burden of writing the getter repeatedly,How can I solve this problem?

Question

Most helpful comment

Write this:

class Form {
    constructor(form: IForm) {
        defineGetter(form, Form);
    }
    get info() {
        return `name is ${this.name}, label is ${this.label}`;
    }
}
interface Form extends IForm { }

All 4 comments

How can I only write a class in this way 😐:

class Form{

    private _form: IForm;

    constructor(form: IForm) {
        this._form = form;
    }

    get name() {
        return this._form.name;
    }

    get label() {
        return this._form.name;
    }

    get value() {
        return this._form.value;
    }

    get width() {
        return this._form.width;
    }

    get type() {
        return this._form.type;
    }

    get sequence() {
        return this._form.sequence;
    }

    // extra getter
    get info() {
        return this.width + this.type;
    }

}

Write this:

class Form {
    constructor(form: IForm) {
        defineGetter(form, Form);
    }
    get info() {
        return `name is ${this.name}, label is ${this.label}`;
    }
}
interface Form extends IForm { }

Can the name of interface and class be the same name? well, I didn‘t write it before. Just wrote a simple interface inheritance

Can the name of interface and class be the same name?

It takes advantage of what TypeScript calls "interface merging". When an interface and a class have the same name, it automatically merges the two. This is in part why it is often recommended not to name your interfaces with an I... which is a convention in many other languages, since there some "automagic" that can happen when the names are the same.

It is best to think as the type system in TypeScript as an "overlay" on top of the underlying JavaScript.

Also to properly type your interface, you should be marking properties that only have a getter as readonly in the interface, which will disallow assignment to the properties within the type system, which would more accurately reflect your runtime intent.

Was this page helpful?
0 / 5 - 0 ratings