Как разобрать объект JSON на объект TypeScript

В настоящее время я пытаюсь преобразовать полученный JSON-объект в класс TypeScript с теми же атрибутами, и я не могу заставить его работать. Что я делаю неправильно?

Класс сотрудников

export class Employee{
    firstname: string;
    lastname: string;
    birthdate: Date;
    maxWorkHours: number;
    department: string;
    permissions: string;
    typeOfEmployee: string;
    note: string;
    lastUpdate: Date;
}

Строка сотрудника

{
    "department": "<anystring>",
    "typeOfEmployee": "<anystring>",
    "firstname": "<anystring>",
    "lastname": "<anystring>",
    "birthdate": "<anydate>",
    "maxWorkHours": <anynumber>,
    "username": "<anystring>",
    "permissions": "<anystring>",
    "lastUpdate": "<anydate>"
    //I will add note later
}

Моя попытка

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);

Ссылка на TypeScript Игровая площадка

Ответ 1

Причина, по которой компилятор позволяет вам передать объект, возвращаемый из JSON.parse в класс, потому что typescript основан на структурном подтипировании.
У вас действительно нет экземпляра Employee, у вас есть объект (как вы видите на консоли), который имеет те же свойства.

Простейший пример:

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);

(код на игровой площадке)

Нет ошибки, потому что a1 удовлетворяет типу A, потому что он имеет все свои свойства, а функция logA может быть вызвана без ошибок времени выполнения, даже если то, что она получает, не является экземпляром A пока он обладает теми же свойствами.

Это отлично работает, когда ваши классы являются простыми объектами данных и не имеют методов, но как только вы вводите методы, тогда все имеет тенденцию ломаться:

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

(код на игровой площадке)


Изменить

Это прекрасно работает:

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);

(код на игровой площадке)

Если вы пытаетесь использовать JSON.parse для своего объекта, если это не строка:

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);

Тогда вы получите ошибку, потому что это не строка, это объект, и если вы уже имеете ее в этой форме, тогда нет необходимости использовать JSON.parse.

Но, как я писал, если вы идете с этим путем, то у вас не будет экземпляра класса, просто объекта, который имеет те же свойства, что и члены класса.

Если вам нужен экземпляр, то:

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>"
});

Ответ 2

Если вы используете TypeScript интерфейс вместо класса, все проще:

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: any = JSON.parse(employeeString); // string to generic object first
let employee: Employee = <Employee>jsonObj;

Если вам нужен класс, простое кастинг не будет работать. Например:

class Foo {
    name: string;
    public pump() { }
}

let jsonObj: any = JSON.parse('{ "name":"hello" }');
let fObj: Foo = <Foo>jsonObj;
fObj.pump(); // crash, method is undefined!

Для класса вам придется написать конструктор, который принимает строку/объект JSON, а затем перебирает свойства для назначения каждого элемента вручную, например:

class Foo {
    name: string;

    constructor(jsonStr: string) {
        let jsonObj: any = JSON.parse(jsonStr);
        for (let prop in jsonObj) {
            this[prop] = jsonObj[prop];
        }
    }
}

let fObj: Foo = new Foo(theJsonString);

Ответ 3

Данные JSON имеют некоторые свойства, которых у вас нет в вашем классе. Для сопоставления Вы можете выполнить обычное сопоставление

export class Employe{ ////
    static parse(json: string) {
           var data = JSON.parse(json);
            return new Employe(data.typeOfEmployee_id, data.firstName.. and others);
       }

}

а также указать конструктор в

Сотрудник

класс

Ответ 4

let employee = <Employee>JSON.parse(employeeString);

Помните: сильные идентификаторы - это время компиляции только после того, как javascript не поддерживает его.

Ответ 5

Прежде всего, вы должны быть уверены, что все атрибуты, поступающие из службы, называются одинаковыми в вашем классе. Затем вы можете проанализировать объект и после этого назначить его новой переменной, что-то вроде этого:

const parsedJSON = JSON.parse(serverResponse);
const employeeObj: Employee = parsedJSON as Employee;

Попробуйте это!