23

I have just started with Angular2 and I've got an issue I cannot really understand.

I have some mock data created as such:

export const WORKFLOW_DATA: Object =
{
    "testDataArray" : [
        { key: "1",              name: "Don Meow",   source: "cat1.png" },
        { key: "2", parent: "1", name: "Roquefort",    source: "cat2.png" },
        { key: "3", parent: "1", name: "Toulouse",   source: "cat3.png" },
        { key: "4", parent: "3", name: "Peppo", source: "cat4.png" },
        { key: "5", parent: "3", name: "Alonzo",     source: "cat5.png" },
        { key: "6", parent: "2", name: "Berlioz", source: "cat6.png" }
    ]
};

Which is then imported in a service and "observed"

import { Injectable } from '@angular/core';

import { WORKFLOW_DATA } from './../mock-data/workflow'
import {Observable} from "rxjs";

@Injectable()
export class ApiService {

  constructor() { }

  getWorkflowForEditor(): Observable<Object>
  {
      return Observable.of( WORKFLOW_DATA );
  }

}

I then have a component which, in the constructor:

constructor( private apiService: ApiService)
    {
        this.apiService.getWorkflowForEditor().subscribe( WORKFLOW_DATA => {
            console.log( WORKFLOW_DATA);
            console.log( WORKFLOW_DATA.testDataArray );
        } );
    }

The first console.log logs an Object of type Object which contains the testDataArray property.

The second console.log, results in an error at compile time:

Property 'testDataArray' does not exist on type 'Object'.

While still logging an array of objects [Object, Object, ..] as intended.

I really do not understand why, I am sure I am doing something wrong, I would love an explanation.

Thank you for any help!

0plus1
  • 4,475
  • 12
  • 47
  • 89

4 Answers4

33

Typescript expects WORKFLOW_DATA to be Object here:

.subscribe( WORKFLOW_DATA => {} )

because you told it so:

  getWorkflowForEditor(): Observable<Object>

But Object doesn't have testDataArray property... You should either tell TypeScript that data can have any properties:

  getWorkflowForEditor(): Observable<any>

or use

console.log( WORKFLOW_DATA["testDataArray"] );
Sasxa
  • 40,334
  • 16
  • 88
  • 102
16

When you tell typescript:

WORKFLOW_DATA: Object

You are telling it that WORKFLOW_DATA is a plain object with no attributes. When you later try to access WORKFLOW_DATA.testDataArray the compiler thinks you misusing the type.

If you want type checking on WORKFLOW_DATA you need to create an interface that describes your object.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • As you can see, other answers suggest using any, I personally feel like using an Interface is the correct way, albeit a bit verbose for something as simple as this. Are interfaces the best practice with Angular2? – 0plus1 Oct 18 '16 at 01:26
  • 1
    The type system is there to help you especially as the application grows. You don't need to use any of it if you don't want to — it has no effect on the final javascript. I (and I think most others) like it because a smart editor provides autocomplete and warns you on making mistakes. If this was my code, I'd probably make a type for the records - `{key: string, parent?:string ..}` and one for the collection that contains the record type - `{testDataArray: recordType[]...` or something like that. – Mark Oct 18 '16 at 01:31
8

The return type if your method is Observable<Object>. So when you subscribe, that will be the type passed. And there is no testDataArray on the Object type. You can do a couple things:

  1. Type the data and return type differently

    WORKFLOW_DATA: { testDataArray: any } = []
    
    getWorkflowForEditor(): Observable<{ testDataArray: any }>
    
  2. Or just type assert the response data to any

    console.log( (<any>WORKFLOW_DATA).testDataArray );
    
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
0

Add Observable

in the method of service.ts which you are subscribing. On the Observable you can refer a type object or mention to accept all type of entries

getResponse(query: string): Observable<any> {
    let data = {
      query: query,
      lang: "en",
      sessionId: "1234567",
    };
    return this.http.post(this.baseURL, data);
  }
Aayush Bhattacharya
  • 1,628
  • 18
  • 17