Reputation: 3094
I'm trying to find the proper and straitforward way to map a complex object into a simpler one.
I wanted to utilize something like this:
interface TransferableResponse<T> {
toServiceResponse(): T;
}
export interface SimpleUserObject {
accessToken: string;
refreshToken: string;
expiresIn: number;
refreshTokenExpiresIn: number;
roleIds: number[];
}
export class ComplexUserObject implements TransferableResponse<SimpleUserObject> {
accessToken: string;
refreshToken: string;
expiresIn: number;
refreshTokenExpiresIn: number;
someRedundancy: Guid;
someWeirdStuff: string;
complexRoles: [{id: number, name: string}];
constructor(init?: Partial<ComplexUserObject>) {
Object.assign(this, init);
}
toServiceResponse(): SimpleUserObject {
return {
...this,
roleIds: this.complexRoles.map(role => role.id)
};
}
}
So in that case I'm creating ComplexUserObject
but then, when calling toServiceResponse()
I would expect to get only the properties specified in SimpleUserObject
. In reality, I'm getting a combination of both (roleIds
, but also complexRoles
, someWeiredStuff
and someRedundancy
).
Long story short, is there a simple, one-line way of saying ...this
but eliminating stuff that are not included in a type?
Pseudo: (...this as SimpleUserObject)
Upvotes: 0
Views: 53
Reputation: 1771
You will unfortunately always need to manually specify the keys from ComplexUserObject
you wish to apply to SimpleUserObject
in some way.
An interface does not exist at runtime, so your code needs to be valid JavaScript when the interfaces are stripped away. There is no JavaScript way of telling the method "take this subset of keys" without explicitly listing those keys somewhere, i.e. manually as keys on the new object, as an array which is iterated, as a reference object which is iterated etc
Your simplest bet is just to list out the new keys
toServiceResponse(): SimpleUserObject {
return {
accessToken: this.accessToken,
refreshToken: this.refreshToken,
expiresIn: this.expiresIn,
refreshTokenExpiresIn: this.refreshTokenExpiresIn,
roleIds: this.complexRoles.map(role => role.id)
};
}
You could also use a class instead of an interface (which would allow the resulting concrete instance to become a typed entity even in JavaScript), but will still suffer the necessary manual listing of keys to instantiate the class, just this time in a constructor instead of directly on the returned object
export class SimpleUserClass {
constructor(public args: SimpleUserObject) {}
}
toServiceResponse(): SimpleUserClass {
return new SimpleUserClass({
accessToken: this.accessToken,
refreshToken: this.refreshToken,
expiresIn: this.expiresIn,
refreshTokenExpiresIn: this.refreshTokenExpiresIn,
roleIds: this.complexRoles.map(role => role.id)
})
}
Upvotes: 1