Странная ошибка при сериализации в JSON массива объектов, имеющих метод to JSON

Я использую NSwag для генерации типов и классов TypeScript для конечных точек API-интерфейса. Полученные классы содержат .toJSON() метод для каждого объекта, который вызывается при сериализации объектов в JSON с использованием JSON.stringify(),

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

angular.js:14199 TypeError: Cannot create property 'code' on string '0'
    at Dashboard.toJSON (App/models/api.js:785:34)
    at JSON.stringify (<anonymous>)

и код, который вызывает его, довольно прост:

console.log(JSON.stringify([
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        }),
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        })
    ]));

Выдержка из класса:

export class Dashboard implements IDashboard {
    code?: string | undefined;
    ...

    constructor(data?: IDashboard) {
        if (data) {
            for (var property in data) {
                if (data.hasOwnProperty(property))
                    (<any>this)[property] = (<any>data)[property];
            }
        }
    }

    init(data?: any) {
        if (data) {
            this.code = data["code"];
            ...
        }
    }

    static fromJS(data: any): Dashboard {
        let result = new Dashboard();
        result.init(data);
        return result;
    }

    toJSON(data?: any) {
        data = data ? data : {};
        data["code"] = this.code;
        ...
        return data; 
    }

    clone() {
        const json = this.toJSON();
        let result = new Dashboard();
        result.init(json);
        return result;
    }
}

Любая идея, почему JSON.stringify() вызывает toJSON() метод с параметром "0"?

1 ответ

Решение

Метод toJSON будет вызываться с одним аргументом, который является именем свойства, к которому this назначен. По сути, ценность вашего интереса не является этим аргументом, но this, который будет привязан к значению, которое вы можете преобразовать. Так как вы звоните stringify с массивом, toJSON будет вызываться с перечислимыми свойствами этого массива, т.е. 0 а также 1, в то время как this будет соответствующий объект Dashboard.

Кроме того, у меня сложилось впечатление, что вы могли бы использовать Object.assign который будет копировать свойства из одного объекта в другой, что, по сути, то, что вы делаете в конструкторе for петля.

Итак, вот как вы могли это сделать. Я удалил оформление машинописного текста и использовал простой JavaScript, но принцип остался прежним:

class Dashboard {
    constructor(data) {
        // Object.assign does essentially what you want with the loop:
        Object.assign(this, data); 
    }

    init(data) {
        return Object.assign(this, data); 
    }

    static fromJS(data) {
        return new Dashboard(data);
    }

    toJSON(key) { 
        // `key` is the key/index of the property in the parent object.
        //    That probably is of no interest to you. You need `this`.
        // Extract properties into plain object, and return it for stringification
        return Object.assign({}, this);
    }

    clone() {
        return new Dashboard(this);
    }
}

console.log(JSON.stringify([
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        }),
        Dashboard.fromJS({
            code: "1212312",
            name: "tresads",
            description: "some description"
        })
    ]));

На самом деле, в данном примере вам не нужно toJSON вообще, поскольку свойства экземпляра Dashboard являются перечисляемыми, и поэтому они все равно будут строковыми. Если по какой-то причине вам это нужно для того, чтобы произошло определенное преобразование, то, конечно, вам все равно нужно включить логику для этого преобразования, поскольку Object.assign это просто копия.

Другие вопросы по тегам