Странная ошибка при сериализации в 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
это просто копия.