You can’t have computed or calculated properties on interfaces since they omit implementation details, that’s the use of interfaces. For example, we can’t do this 🛑
export interface IUser { firstName?: string; lastName?: string; fullName?: string = this.firstName + this.lastName; }
but we can just declare it in the interface and implement it in a class
export interface IUser { firstName?: string; lastName?: string; fullName?: string; }
export class User implements IUser { constructor(public firstName?: string, public lastName?: string) {} get fullName(): string { return `${this.firstName} ${this.lastName}`; } }
now let's see how we can instantiate those class
User user = new User('Jhon', 'Doe'); console.log(user.fullName); // Jhon Doe
the problem I had was the data was coming from a service
this.userService.query().pipe( filter((res: HttpResponse) => res.ok), map((res: HttpResponse) => res.body) ) .subscribe((data: IUser[])=>{ this.users = data; })
changing declared type of reponses won't make a difference 🤷
this.userService.query().pipe( filter((res: HttpResponse) => res.ok), map((res: HttpResponse) => res.body) ) .subscribe((data: User[])=>{ this.users = data; })
neither 'cast' (which in typescript its not casting but just an assertion) response objects to class type
this.userService.query().pipe( filter((res: HttpResponse) => res.ok), map((res: HttpResponse) => res.body) ) .subscribe((data: IUser[])=>{ this.users = data.map(value => (value as User)); })
i tried to did it by copying properties to a new object of the correct class with spread operator syntax
this.userService.query().pipe( filter((res: HttpResponse) => res.ok), map((res: HttpResponse) => res.body) ) .subscribe((data: IUser[])=>{ this.users = data.map(value => { return {...new User(), ...value} as User; }); })
it turns out spread syntax produce a plain or literal object so it can't be used to accomplish what we we're trying to do. We need to use the Object.assign method (be aware there could be undesirable or unexpected results).
this.userService.query().pipe( filter((res: HttpResponse) => res.ok), map((res: HttpResponse) => res.body) ) .subscribe((data: IUser[])=>{ this.users = data.map(value => { return Object.assign(new User(), value); }); })
great! 😄
UPDATE: 2019-06-24
Although it worked I was assuming it would only be used in just one component, and of course it didn't.
So, it's way easier to just add the computed field in the domain object or DTO on the server, i.e.
UserDTO.java
public String getFullName() { return getFirstName() + " " + getLastName(); }
If you can't change the model or just insist on computing at client side, then it's better if you do it at a central location, i.e. the Service
query(req?: any): Observable { return this.http.get('/api/users', { params: options, observe: 'response' }) .pipe( map(res => { const users = res.body.map(user => { return Object.assign(new User(), user); }); return new HttpResponse({...res, body: users}); }) ); }
sources:
https://stackoverflow.com/questions/53238881/computed-property-in-typescript
https://stackoverflow.com/questions/49937677/how-to-merge-class-instances-in-typescript