Typescript get properties names in constructor of extended class

Viewed 823

I am new to typescript and I am trying to learn how to use classes.

My goal would be to create a constructor that can take an object as parameter:

{
    first_name: 'Bill',
    foo: 'Bar'
}

And that the constructor would automatically fill the properties of my instanciated class, but only the declared properties:

export default class User {
    // Because of "this[key] = data[key]", I need to tell my class 
    // that the class User is a key:string => value:any structure
    [key: string]:any;

    // Here, I define a public property first_name
    public first_name:string;

    constructor (data:{[index:string] : any}) {
        // Here, I get the properties of my Object
        let properties = this.getPublicProperties();

        // I assign the value only if the key is part of my properties
        Object.keys(data).forEach((key:string) => {
            if (typeof properties.find((x:string) => x === key) !== 'undefined') {
                this[key] = data[key];
            }
        })
    }

    getPublicProperties () {
        // I'd like that to be based on defined properties above with "public first_name:string"
        // The ideal would be that I could define "private" properties that would not be able 
        // to be filled with that method.

        return ['first_name'];
    }
}

Let's try with this main code:

import User from './models/User'

let user:User = new User({
    first_name: 'Mathieu',
    foo: 'bar'
});

console.log(user);

Result:

User { first_name: 'Mathieu' }

Question: So how could I change my getPublicProperties() in order to automatically grab my properties?

The only solution I came to was to initiate my public properties to null:

export default class User {
    [key: string]:any;

    public first_name:string = null;

    private foo:string;

    ...

    getPublicProperties () {
        return Object.getOwnPropertyNames(this);
    }
}

Now, let's say that solution works, I would like to abstract this behaviour to another class:

export default class Model {
    [key: string]:any;

    construct (data:{[index:string] : any}) {
        let properties = this.getPublicProperties();
        Object.keys(data).forEach((key:string) => {
            if (typeof properties.find((x:string) => x === key) !== 'undefined') {
                this[key] = data[key];
            }
        })
    }

    getPublicProperties () {
        return Object.getOwnPropertyNames(this);
    }
}

import Model from "./Model";

export default class User extends Model{

    public first_name:string = null;

    private foo:string;

    constructor (data:{[index:string] : any}) {
        super();
        super.construct(data);
    }
}

As you can see in my constructor, I have to call super() before calling another method of the constructor, because if I don't, the getPublicProperties abstracted method would not work in my construct() method.

Question: Am I doing it right, or do I miss something in the inheritance functionalities?

0 Answers
Related