2016-04-29 12 views
1

ich eine Modellklasse wie diese:Warum von JSON Literal nicht Casting gibt keine Funktionen umfasst

export class Task { 

    public name: string; 
    public status: string = "todo"; 

    public completeTask(): void { 
     this.status = "done"; 
    } 
} 

und einen Service, der eine Aufgabe ruft:

export class TaskService { 

    constructor(private _http: Http) {} 

    public getTask(): Observable<Task> { 
     return this._http 
      .get("url") 
      .map(res => res.json().data as Task) 
    } 
} 

Als ich dann zu nennen versuchen die completeTask Funktion auf die Aufgabe erhalte ich die Fehlermeldung:

TypeError: task.completeTask() is not a function

ich das gleiche Ergebnis, wenn ich eine JSO werfen N literales Objekt für eine Aufgabe.

let task: Task = <Task>{ name: "Make some coffee" } 
task.completeTask(); // Results in error 

Mache ich etwas falsch? Wie kann ich sicherstellen, dass Funktionen enthalten sind?

+1

Das Problem ist, dass dies nicht eine Art _cast_ ist, sondern ein Geben Sie _assertion_ ein, was keine Laufzeitunterstützung für die Typkonvertierung bedeutet. Sie sagen dem Compiler, dass 'task' vom Typ' Task' ist, aber tatsächlich ist es nur vom Typ 'Object', der von' json' geparst wurde. Dieses Problem mit JSON ist ein etwas häufiges Problem in TypeScript, für das ich gerade an einer Lösung arbeite (mehr wie "_testing_ it") mit Decorators. –

Antwort

2

Tatsächlich haben Sie beim Casting keine Instanz des Typs, den Sie gewirkt haben. Sie deklarieren nur ein Objekt mit der Literalform, keine Instanz der Aufgabe.

Wenn es nur eine Möglichkeit ist, die von TypeScript bereitgestellt wird, um zu überprüfen, ob das gegossene Objekt der Struktur des Typen folgt. Aber es ist zur Laufzeit nicht nur zur Design-/Kompilierzeit etwas.

Wenn Sie in der Lage sein wollen Methoden des Typs zu verwenden, müssen Sie ein neues Objekt instanziiert auf den Inhalt basiert:

public getTask(): Observable<Task> { 
    return this._http 
     .get("url") 
     .map(res => { 
      let content = res.json().data; 
      let task = new Task(); 
      task.name = content.name; 
      task.status = content.status; 
      return task; 
     }); 
} 

Sehen Sie diese Frage für weitere Informationen:

bearbeiten

Im Anschluss an die Bemerkung des @ ssube könnten Sie die Task Klasse wie folgt erklären:

export class Task { 
    (...) 

    constructor(obj:{name:string, status:string}) { 
    this.name = obj.name; 
    this.status = obj.status; 
    } 

    (...) 
} 

diese Weise wird die instantiate einfacher wäre:

public getTask(): Observable<Task> { 
    return this._http 
     .get("url") 
     .map(res => new Task(res.json().data)); 
} 
+0

Oh ich sehe, macht Sinn. Ich hatte gehofft, dass es eine einfachere Lösung geben würde. – Aetherix

+0

In der Tat nein. Es ist, weil es nicht zur Laufzeit ist ;-) –

+1

@ThierryTemplier Es wäre einfach, wenn Sie einen 'Konstruktor (Name, Status)' auf Ihrer 'Task' Klasse hätten. – ssube

Verwandte Themen