Makla Makla - 4 months ago 23
TypeScript Question

How to dynamically assign value to class property in TypeScript

I would like to dynamically assign multiple properties to MyClass in TypeScript so there is no need to write multiple lines of code for setting class properties. I wrote the following code:

interface IMy
{
visible?: boolean;
text?: string;
}

class MyClass
{
element: JQuery;

assing(o: IMy): void
{
for (let [key, value] of o.entries())
{
if (typeof value !== "undefined")
this[key] = value;
}
}

get visible(): boolean
{
return this.element.is(":visible");
}

set visible(visible: boolean)
{
this.element.css("display", visible ? "" : "none");
}

get text(): string
{
return this.element.html();
}

set text(text: string)
{
this.element.html(text);
}
}

let t = new MyClass();
t.assign({ visible: true });
//instead t.visible = true;

//or

t.assign({ text: "Something" });
//instead t.text = "something";

//or

t.assign({ text: "Something", visible: false });
//instead t.visible = true;
// t.text = "something";


but, I have problems in line
this[key] = value;
with error:


Index signature of object type implicitly has an 'any' type.


What I need to change or my approach is completely wrong?

It would also be a good solution for setting default properties in constructor when interface is constructor parameter.

Edited:

About entries I really liked them so I am using this code:

//extensions.d.ts
interface Object
{
entries<T>(): [string, T][];
entries(): [string, any][];
}
//exntesion.js !!note js not ts
if (!Object.entries)
{
Object.entries = function* entries(obj)
{
for (let key of Object.keys(obj))
{
yield [key, obj[key]];
}
};
}


Edited 2:

The primary idea was to solve problems for overloading constructor where you could set only desired properties.

Here is the complete code if someone else finds it usable.

interface IMy
{
prop1?: boolean;
prop2?: string;
prop3?: string;
prop4?: number;
}

class MyClass implements IMy
{
prop1: boolean = false;
prop2: string = "";
prop3: string = "Something";
prop4: number = 0;

constructor(properties: IMy)
{
this.assing(properties);
}

assing(o: IMy): void
{
let that = (<any>this);
for (let key in o)
{
if (o.hasOwnProperty(key))
{
let value = (<any>o)[key];
if (typeof value !== "undefined" && typeof that[key] !== "undefined")
that[key] = value;
}
}
}

}

let my1 = new MyClass({ prop1: true });
let my2 = new MyClass({ prop2: "SomeText", prop3: "Anything" });
//I set prop2 and prop3
let my3 = new MyClass({ prop4: 10 });
//I set prop4 (fourth parameter)

console.log(my1, my2, my3);

Answer

The error itself comes from the --noImplicitAny compiler option. If you'd remove it, the error would go away. But I believe and it's not a bad thing to have.

You'd need to somehow add a type annotation to key, which seems not to be problematic with in a for .. of loop.

I think the approach is not bad, but you'd need to rewrite iteration over properties a bit differently.

As an aside, I assume you're alse targeting ES6 (for the compiler not to complain about .entries(), which looks like an ES6 feature. It looks like it's for arrays, not objects.

EDIT:

inspired by another SO answer - to make the error go away, you could add a cast to any, like so:

(<any>this)[key] = value;

The above about using .entries() still applies, though.