Reputation: 3158
So I have a api call that brings back information about a user:
data: {
name: 'Some One',
age: 100,
gender: 'male'
// etc
}
And I'm setting this to a class object.
class User {
public data: any = {}
constructor(data: any):void {
this.updateData(data)
}
updateData(data) {
for (const property in data) {
if (Object.prototype.hasOwnProperty.call(data, property) &&
typeof data[property] !== 'function') {
this.data[property] = data[property]
}
}
}
}
So when you do a const user = new User(userInfoFromApi)
and console.log(user), it sends up looking like the same way it came in from the API.
What I want to do is reference user.name
instead of user.data.name
. Is that possible?
Something I tried was setting
const self = this
And then self[property] = data[property]
but Typescript did NOT like that.
Upvotes: 0
Views: 849
Reputation: 2351
interface IUser {
name: string;
age: number;
gender: "male" | "female";
}
class Base<T> {
public readonly data: T;
constructor(data: T) {
this.data = data;
}
// i suppose updateData allow update partly
public updateData(data: Partial<T>) {
for (const property in data) {
if (
Object.prototype.hasOwnProperty.call(data, property) &&
typeof data[property] !== "function"
) {
this.data[property] = data[property]!;
}
}
}
}
// first way use getter setter
class User extends Base<IUser> implements IUser {
public get name() {
return this.data.name;
}
public get age() {
return this.data.age;
}
public get gender() {
return this.data.gender;
}
public set name(name) {
this.data.name = name;
}
public set age(age) {
this.data.age = age;
}
public set gender(gender) {
this.data.gender = gender;
}
}
const user1 = new User({ name: "", gender: "female", age: 10 });
user1.updateData({ name: "part of value" });
user1.age = 2;
console.log(user1.data); // { name: 'part of value', gender: 'female', age: 2 }
console.log(user1.name); // part of value
// second way use Object.defineProperty
function create<T extends object>(data: T): Base<T> & T {
const target = new Base(data);
for (const property in data) {
if (
Object.prototype.hasOwnProperty.call(data, property) &&
typeof data[property] !== "function"
) {
Object.defineProperty(target, property, {
get: function (this: Base<T>) {
return this.data[property];
},
set: function (this: Base<T>, value) {
this.data[property] = value;
},
});
}
}
return target as never;
}
const user2 = create<IUser>({ name: "", gender: "female", age: 10 });
user2.updateData({ name: "part of value" });
user2.age = 2;
console.log(user2.data); // { name: 'part of value', gender: 'female', age: 2 }
console.log(user2.name); // part of value
Upvotes: 1
Reputation: 333
You can do (this as any)['some_random_properties']
but this basically bypassed the type checking provided so you have to pretty careful about that.
I would suggest to define the properties exactly in class because that is actually what the type checking is for.
Upvotes: 0