Reputation: 1756
I have a simple model:
export class Profile extends ServerData {
name: string;
email: string;
age: number;
}
When I am make a call to the server (Angular 4, $http) I often get the following response:
{
name: string;
email: string;
}
The age
property is missing.
Is there any way to use my model and create a default age in case it is missing? I would prefer not to have to create 2 separate models if possible.
I don't want to create the age as an optional property - I need it, even if it is just with an incorrect default.
UPDATE:
This is the call I making to the server:
results-manager.component.ts:
this.resultsManagerService.getResults(this.config.request.action, this.pagingAndSorting, this.args).subscribe(
results => {
this.results = this.results.concat(results as Profile[]);
results-manager.service.ts:
getResults(action: string, pagingAndSorting: PagingAndSorting, args: string[]): Observable<Profile[]> {
return this.apiService.callServer(
pagingAndSorting,
action,
...args );
}
The request works and I receive the response, but even if I define the default values (as suggested by @msanford's answer) they get removed when I receive the response back in the component. Likewise if i add a constructor to the model (as per Mike Tung's answer).
It seems like the backend response is completely overwriting the model - not just assigning the values.
How can I get it to just assign the values to the model and not remove the values it does not return?
Upvotes: 35
Views: 130936
Reputation: 1
export class Cell {
constructor(
public name: string = "",
public rowspan: number = 1,
public colspan: number = 1
){ }
}
export class Table {
public c1 = new Cell()
public c2 = new Cell()
public c3 = new Cell()
}
Upvotes: 0
Reputation: 1964
The reason you're seeing overwriting properties is due to type erasure in TypeScript. TypeScript has no idea what types of objects are assigned to its variables during runtime. This would seem somewhat strange to you if you're coming not from a java / c# background.
Because in the end , it's just JavaScript. And JavaScript doesn't enforce strict type checking.
In order to ensure that your profile objects always have an age property, you could create your own objects then copy over the values you get from the response. This is the usual approach when it comes to wire format to domain object mapping.
To do this first create your domain model, a Profile class with a default age property in this case.
export class Profile {
constructor(
public name: string,
public email: string,
public age: number = 0) { }
}
Then map your response to the domain model.
this.resultsManagerService.getResults(this.config.request.action, this.pagingAndSorting, this.args).subscribe(
results => {
let res = (results as Profile[]).map((profile) => new Profile(profile.name, profile.email, profile.age));
this.results = this.results.concat(res);
});
Upvotes: 24
Reputation: 12227
Yes, easily, and you don't need to add a class constructor.
export class Profile extends ServerData {
name: string;
email: string;
age: number = 0;
}
The ability to define default values is one of the main things that differentiates a class
from an interface
.
For this to work you need to call new Profile()
somewhere in your code, otherwise a class instance won't be created and you won't have defaults set, because the above TypeScript will compile to the following JavaScript:
var Profile = /** @class */ (function () {
function Profile() {
this.age = 0;
}
return Profile;
}());
So just using it for type assertion at compile-time isn't sufficient to set a default at run-time.
See it in action in the TypeScript Playground.
Upvotes: 51
Reputation: 191749
You can't quite do this automatically, but you could set defaults for a function (possibly the class constructor):
function makeProfile({ name = '', email = '', age = 0 }) {
const person = new Profile;
person.name = name;
person.email = email;
person.age = age;
return person;
}
Now if you call makePerson({ name: 'name', email: 'email' })
it will return a Person
with age = 0
.
Upvotes: 4
Reputation: 4821
You don't need to do much aside from use a constructor.
export class Profile extends ServerData {
name: string;
email: string;
age: number;
constructor(name: string = '', email: string = '', age: number = null) {
this.name = name;
this.email = email;
this.age = age;
}
}
This will create default params for things you are missing.
Upvotes: 5