I've some typescript classes instances in my angular app that I've to save to firebase. Firebase isn't supporting custom classes, so I found this: that seems well fitted for me.
So now I'm creating my object, and trying to convert it.
Here is my object.
export class Trip {
id: string;
owner: string;
name: string;
@Type(() => Date)
startDate: Date;
@Type(() => Date)
endDate: Date | undefined;
coverImageUrl: string;
@Type(() => Itinerary)
itinerary: Itinerary;
constructor() {
this.itinerary = new Itinerary();
}
}
export class Itinerary {
@Type(() => ItineraryStats)
stats: ItineraryStats;
@Type(() => Step, {
discriminator: {
property: '__type',
subTypes: [
{ value: ActivityStep, name: 'ActivityStep' },
{ value: NightStep, name: 'NightStep' },
{ value: PointOfInterest, name: 'PointOfInterest' },
{ value: TravelStep, name: 'TravelStep' },
],
},
})
steps: Step[];
constructor() {
this.steps = Step[0];
this.stats = new ItineraryStats();
}
}
export class ItineraryStats {
///In days
duration: number;
//in hours
driveTime: number;
//in kilometers
driveDistance: number;
averageDriveDistancePerDay(): number {
return this.driveDistance / this.duration;
}
averageDriveTimePerDay(): number {
return this.driveTime / this.duration;
}
}
export abstract class Step {
@Type(() => Date)
start: Date;
@Type(() => Date)
end: Date;
duration: number;
enforcedStartStop: boolean;
warning: string;
}
export class ActivityStep extends StopStep {
duration: number;
constructor() {
super();
this.id = Guid.newGuid();
}
}
export class NightStep extends StopStep {
nightNumber: number;
numberOfNight: number;
}
export class PointOfInterest {
@Type(()=>PointOfInterest)
type: PointOfInterest;
}
export class TravelStep extends Step {
@Type(() => TravelMode)
Mode: TravelMode;
PolyLines: string;
}
I'm creating one "trip" and trying to convert it:
const trip = new Trip();
trip.owner= firebase.auth().currentUser.uid;
trip.name= action.name;
trip.startDate = action.startDate,
trip.endDate = action.endDate;
console.log(trip);
const converted = classToPlain(trip)
But I get this:
ERROR TypeError: Cannot read property 'constructor' of undefined
at TransformOperationExecutor.js:207
at Array.find (<anonymous>)
at TransformOperationExecutor.transform (TransformOperationExecutor.js:207)
at TransformOperationExecutor.transform (TransformOperationExecutor.js:266)
at ClassTransformer.classToPlain (ClassTransformer.js:10)
at classToPlain (index.js:8)
at Object.toFirestore (trips.firestore.ts:16)
at ma (index.cjs.js:15983)
at n.set (index.cjs.js:15359)
at AngularFirestoreDocument.set (angular-fire-firestore.js:512)
The object I just created:
I guess either my object is in an improper state or I've something poorly defined, but I can't find what?
I've some typescript classes instances in my angular app that I've to save to firebase. Firebase isn't supporting custom classes, so I found this: https://github./typestack/class-transformer that seems well fitted for me.
So now I'm creating my object, and trying to convert it.
Here is my object.
export class Trip {
id: string;
owner: string;
name: string;
@Type(() => Date)
startDate: Date;
@Type(() => Date)
endDate: Date | undefined;
coverImageUrl: string;
@Type(() => Itinerary)
itinerary: Itinerary;
constructor() {
this.itinerary = new Itinerary();
}
}
export class Itinerary {
@Type(() => ItineraryStats)
stats: ItineraryStats;
@Type(() => Step, {
discriminator: {
property: '__type',
subTypes: [
{ value: ActivityStep, name: 'ActivityStep' },
{ value: NightStep, name: 'NightStep' },
{ value: PointOfInterest, name: 'PointOfInterest' },
{ value: TravelStep, name: 'TravelStep' },
],
},
})
steps: Step[];
constructor() {
this.steps = Step[0];
this.stats = new ItineraryStats();
}
}
export class ItineraryStats {
///In days
duration: number;
//in hours
driveTime: number;
//in kilometers
driveDistance: number;
averageDriveDistancePerDay(): number {
return this.driveDistance / this.duration;
}
averageDriveTimePerDay(): number {
return this.driveTime / this.duration;
}
}
export abstract class Step {
@Type(() => Date)
start: Date;
@Type(() => Date)
end: Date;
duration: number;
enforcedStartStop: boolean;
warning: string;
}
export class ActivityStep extends StopStep {
duration: number;
constructor() {
super();
this.id = Guid.newGuid();
}
}
export class NightStep extends StopStep {
nightNumber: number;
numberOfNight: number;
}
export class PointOfInterest {
@Type(()=>PointOfInterest)
type: PointOfInterest;
}
export class TravelStep extends Step {
@Type(() => TravelMode)
Mode: TravelMode;
PolyLines: string;
}
I'm creating one "trip" and trying to convert it:
const trip = new Trip();
trip.owner= firebase.auth().currentUser.uid;
trip.name= action.name;
trip.startDate = action.startDate,
trip.endDate = action.endDate;
console.log(trip);
const converted = classToPlain(trip)
But I get this:
ERROR TypeError: Cannot read property 'constructor' of undefined
at TransformOperationExecutor.js:207
at Array.find (<anonymous>)
at TransformOperationExecutor.transform (TransformOperationExecutor.js:207)
at TransformOperationExecutor.transform (TransformOperationExecutor.js:266)
at ClassTransformer.classToPlain (ClassTransformer.js:10)
at classToPlain (index.js:8)
at Object.toFirestore (trips.firestore.ts:16)
at ma (index.cjs.js:15983)
at n.set (index.cjs.js:15359)
at AngularFirestoreDocument.set (angular-fire-firestore.js:512)
The object I just created:
I guess either my object is in an improper state or I've something poorly defined, but I can't find what?
Share Improve this question asked Mar 9, 2021 at 19:51 J4NJ4N 20.8k42 gold badges222 silver badges384 bronze badges 3-
Please share
Type
decorator – captain-yossarian from Ukraine Commented Mar 15, 2021 at 13:33 - @captain-yossarian this decorator is from the library I linked: github./typestack/class-transformer/blob/develop/src/… – J4N Commented Mar 15, 2021 at 14:52
- 1 You should create a Minimal, Reproducible Example – TmTron Commented Mar 15, 2021 at 19:20
1 Answer
Reset to default 2 +200The error lies in the definition of Itinerary
, more specifically the code line this.steps = Step[0];
which sets the variable to undefined and most likely wasn't intentional. The class-transformer
library can deal with property steps
being an empty array, array of steps, or not existing in the first place but crashes when the value is set to undefined.
export class Itinerary {
@Type(() => ItineraryStats)
stats: ItineraryStats;
@Type(() => Step, {
discriminator: {
property: '__type',
subTypes: [
{ value: ActivityStep, name: 'ActivityStep' },
{ value: NightStep, name: 'NightStep' },
{ value: PointOfInterest, name: 'PointOfInterest' },
{ value: TravelStep, name: 'TravelStep' },
],
},
})
steps: Step[];
constructor() {
// Step[0] causes the crash, because its undefined, either dont set it or
// set it to this.steps = []
this.steps = Step[0];
this.stats = new ItineraryStats();
}
}
More details:
Due to the use of discriminators on property steps
the corresponding logic kicked in and pared the constructors defined under subTypes
, with the constructor of the current value to find the correct subtype name:
if (this.transformationType === TransformationType.CLASS_TO_PLAIN) {
subValue[targetType.options.discriminator.property] = targetType.options.discriminator.subTypes.find(
subType => subType.value === subValue.constructor
).name;
}
link to github
Step[0]
being undefined eventually made this line subValue.constructor
crash.