As @jonrsharpe explained, the problem is that FileBackend does not return proper Task objects. Rather, it returns raw objects with the properties of a Task, which do not have any of the methods. I wrongly assumed the Task objects were automatically constructed thanks to the type hints, but this was not the case.
The solution would be to construct a Task object from the retrieved items. For example, defining a factory method like this (the dates are being parsed using Date.parse() per as the MDN documentation):
public static tryFromRawObject(obj: {id?: number, name: string, status: string, creationTime: string, lastModificationTime: string}): Task {
let parsedCreationTime = Date.parse(obj.creationTime);
if (isNaN(parsedCreationTime)) {
throw new TypeError(`Failed to construct Date object from value: creationTime=${obj.creationTime}`);
}
let parsedLastModificationTime = Date.parse(obj.lastModificationTime);
if (isNaN(parsedLastModificationTime)) {
throw new TypeError(`Failed to construct Date object from value: lastModificationTime=${obj.creationTime}`);
}
if (!Object.values(TaskStatus).includes(obj.status as TaskStatus)) {
throw new TypeError(`Failed to construct TaskStatus object from value: status=${obj.status}`);
}
return new Task({
id: obj.id,
name: obj.name,
status: obj.status as TaskStatus,
creationTime: new Date(parsedCreationTime),
lastModificationTime: new Date(parsedLastModificationTime),
});
}
And then invoke it from the TaskRepository:
private async readStream(): Promise<Array<Task>>{
const tasks: Array<{id?: number, name: string, status: string, creationTime: string, lastModificationTime: string}> = [];
tasks.push(...await this.backend.json());
return tasks.map(Task.tryFromRawObject);
}