Reputation: 1099
I am currently trying to convert my received JSON Object into a TypeScript class with the same attributes and I cannot get it to work. What am I doing wrong?
Employee Class
export class Employee{
firstname: string;
lastname: string;
birthdate: Date;
maxWorkHours: number;
department: string;
permissions: string;
typeOfEmployee: string;
note: string;
lastUpdate: Date;
}
Employee String
{
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": <anynumber>,
"username": "<anystring>",
"permissions": "<anystring>",
"lastUpdate": "<anydate>"
//I will add note later
}
My Attempt
let e: Employee = new Employee();
Object.assign(e, {
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": 3,
"username": "<anystring>",
"permissions": "<anystring>",
"lastUpdate": "<anydate>"
});
console.log(e);
Upvotes: 74
Views: 259189
Reputation: 162
Here's a concise solution that works well for simple "flat" objects:
let listOfObjectsWithMethods = listFromBackend.map( o => Object.assign(new MyType(), o));
Once you perform this transformation, you will be able to access the methods of objects declared in the MyType class
Upvotes: 0
Reputation: 8078
If you use a TypeScript interface instead of a class, things are simpler:
export interface Employee {
typeOfEmployee_id: number;
department_id: number;
permissions_id: number;
maxWorkHours: number;
employee_id: number;
firstname: string;
lastname: string;
username: string;
birthdate: Date;
lastUpdate: Date;
}
let jsonObj = JSON.parse(employeeString); // string to "any" object first
let employee = jsonObj as Employee;
If you want a class, however, simple casting won't work. For example:
class Foo {
name: string;
public pump() { }
}
let jsonObj = JSON.parse('{ "name":"hello" }');
let fObj = jsonObj as Foo;
fObj.pump(); // crash, method is undefined!
For a class, you'll have to write a constructor which accepts a JSON string/object and then iterate through the properties to assign each member manually, like this:
class Foo {
name: string;
constructor(jsonStr: string) {
let jsonObj = JSON.parse(jsonStr);
for (let prop in jsonObj) {
this[prop] = jsonObj[prop];
}
}
}
let fObj = new Foo(theJsonString);
Upvotes: 76
Reputation: 377
You can perform this operation using syntax "as"?
async getProfile(): Promise<Contact> {
const url: string = this.baseApi;
const response = await this.http.get(url).toPromise()
return JSON.parse(response.json()) as Contact;
}
Upvotes: 0
Reputation: 662
you can make a new object of your class and then assign it's parameters dynamically from the JSON object's parameters.
const employeeData = JSON.parse(employeeString);
let emp:Employee=new Employee();
const keys=Object.keys(employeeData);
keys.forEach(key=>{
emp[key]=employeeData[key];
});
console.log(emp);
now the emp is an object of Employee containing all fields of employeeString's Json object(employeeData);
Upvotes: 0
Reputation: 4431
You can cast the the json as follows:
Given your class:
export class Employee{
firstname: string= '';
}
and the json:
let jsonObj = {
"firstname": "Hesham"
};
You can cast it as follows:
let e: Employee = jsonObj as Employee;
And the output of console.log(e);
is:
{ firstname: 'Hesham' }
Upvotes: 0
Reputation: 724
Your JSON data may have some properties that you do not have in your class. For mapping You can do simple custom mapping
export class Employe{ ////
static parse(json: string) {
var data = JSON.parse(json);
return new Employe(data.typeOfEmployee_id, data.firstName.. and others);
}
}
and also specifying constructor in your Employee
class.
Upvotes: 6
Reputation: 5
if it is coming from server as object you can do
this.service.subscribe(data:any) keep any type on data it will solve the issue
Upvotes: -3
Reputation: 1591
i like to use a littly tiny library called class-transformer.
it can handle nested-objects, map strings to date-objects and handle different json-property-names a lot more.
Maybe worth a look.
import { Type, plainToClass, Expose } from "class-transformer";
import 'reflect-metadata';
export class Employee{
@Expose({ name: "uid" })
id: number;
firstname: string;
lastname: string;
birthdate: Date;
maxWorkHours: number;
department: string;
@Type(() => Permission)
permissions: Permission[] = [];
typeOfEmployee: string;
note: string;
@Type(() => Date)
lastUpdate: Date;
}
export class Permission {
type : string;
}
let json:string = {
"uid": 123,
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": 1,
"username": "<anystring>",
"permissions": [
{'type' : 'read'},
{'type' : 'write'}
],
"lastUpdate": "2020-05-08"
}
console.log(plainToClass(Employee, json));
```
Upvotes: 3
Reputation: 3597
Try to use constructor procedure in your class.
Object.assign
is a key
Please take a look on this sample:
class Employee{
firstname: string;
lastname: string;
birthdate: Date;
maxWorkHours: number;
department: string;
permissions: string;
typeOfEmployee: string;
note: string;
lastUpdate: Date;
constructor(original: Object) {
Object.assign(this, original);
}
}
let e = new Employee({
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": 3,
"username": "<anystring>",
"permissions": "<anystring>",
"lastUpdate": "<anydate>"
});
console.log(e);
Upvotes: 0
Reputation: 21
First of all you need to be sure that all attributes of that comes from the service are named the same in your class. Then you can parse the object and after that assign it to your new variable, something like this:
const parsedJSON = JSON.parse(serverResponse);
const employeeObj: Employee = parsedJSON as Employee;
Try that!
Upvotes: 2
Reputation: 164397
The reason that the compiler lets you cast the object returned from JSON.parse
to a class is because typescript is based on structural subtyping.
You don't really have an instance of an Employee
, you have an object (as you see in the console) which has the same properties.
A simpler example:
class A {
constructor(public str: string, public num: number) {}
}
function logA(a: A) {
console.log(`A instance with str: "${ a.str }" and num: ${ a.num }`);
}
let a1 = { str: "string", num: 0, boo: true };
let a2 = new A("stirng", 0);
logA(a1); // no errors
logA(a2);
There's no error because a1
satisfies type A
because it has all of its properties, and the logA
function can be called with no runtime errors even if what it receives isn't an instance of A
as long as it has the same properties.
That works great when your classes are simple data objects and have no methods, but once you introduce methods then things tend to break:
class A {
constructor(public str: string, public num: number) { }
multiplyBy(x: number): number {
return this.num * x;
}
}
// this won't compile:
let a1 = { str: "string", num: 0, boo: true } as A; // Error: Type '{ str: string; num: number; boo: boolean; }' cannot be converted to type 'A'
// but this will:
let a2 = { str: "string", num: 0 } as A;
// and then you get a runtime error:
a2.multiplyBy(4); // Error: Uncaught TypeError: a2.multiplyBy is not a function
This works just fine:
const employeeString = '{"department":"<anystring>","typeOfEmployee":"<anystring>","firstname":"<anystring>","lastname":"<anystring>","birthdate":"<anydate>","maxWorkHours":0,"username":"<anystring>","permissions":"<anystring>","lastUpdate":"<anydate>"}';
let employee1 = JSON.parse(employeeString);
console.log(employee1);
If you're trying to use JSON.parse
on your object when it's not a string:
let e = {
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": 3,
"username": "<anystring>",
"permissions": "<anystring>",
"lastUpdate": "<anydate>"
}
let employee2 = JSON.parse(e);
Then you'll get the error because it's not a string, it's an object, and if you already have it in this form then there's no need to use JSON.parse
.
But, as I wrote, if you're going with this way then you won't have an instance of the class, just an object that has the same properties as the class members.
If you want an instance then:
let e = new Employee();
Object.assign(e, {
"department": "<anystring>",
"typeOfEmployee": "<anystring>",
"firstname": "<anystring>",
"lastname": "<anystring>",
"birthdate": "<anydate>",
"maxWorkHours": 3,
"username": "<anystring>",
"permissions": "<anystring>",
"lastUpdate": "<anydate>"
});
Upvotes: 45
Reputation: 8992
let employee = <Employee>JSON.parse(employeeString);
Remember: Strong typings is compile time only since javascript doesn't support it.
Upvotes: 7