问题
I'm new in typescript, and i'm trying to rewrite our application from es2016 to typescript. My task is to have a class with data property and make each element from data object available as class property.
I get stuck on this javascript code:
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
It is pretty easy to use getter/setters for typescript, but i get confused if i can create them dynamically?
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
super()
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
tsc -t ES2016 --lib "es2016","dom" models.ts
WIll give this error:
models.ts(33,40): error TS2345: Argument of type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to parameter of type 'PropertyDescriptor & ThisType<any>'.
Type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to type 'PropertyDescriptor'.
Types of property 'get' are incompatible.
Type '(value: any) => any' is not assignable to type '() => any'.
And i don't know how to get rid of this problem.
回答1:
thanks to the https://github.com/epicgirl1998, she helped me to find the solution. I'll post it here:
the error is that the getter has a value parameter even though getters aren't passed any value
i replaced it with get: function() { return this.data[key]; }, and now the only error is that there's a super call in the class which is only needed if the class extends another class
also, this inside the accessors doesn't refer to the class instance, but using arrow functions for them should fix it
try this:
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: () => { return this.data[key]; },
set: (value:any) => {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
回答2:
In typescript, you generally don't need to create objects with methods and properties dynamically. You either create instances of classes, or you type your data using an interface.
If all you want is to convert loaded (json) data to typed data, you can use an interface that describes the structure of your json data.
interface describes the properties of actor data
interface Actor {
name: string;
height: number;
}
fetch generic json data from somewhere
let data : any = getSingleActorData();
type the actor to an interface and put it in an actor array
let actorData : Actor[] = [];
actorData.push(data as Actor);
Now your IDE will allow you to access the name and height of the actor variable:
console.log(actorData[0].name);
If you do want a complete 'object' with getters and setters you can create an Actor class and then instantiate it with the data you loaded:
class Actor {
private _name:string;
private _height:string;
get name {}
set name {}
get height {}
set height {}
constructor(name:string, height:number){
}
}
And then you can put your json data in an actor instance:
actorData.push(new Actor(jsondata.name, jsondata.height));
来源:https://stackoverflow.com/questions/45236274/is-it-possible-to-create-dynamic-getters-setters-in-typescript