Cast Typescript ( ERROR Typeerror )

Asked

Viewed 132 times

0

The problem is this, through a service(ModeloService), receive an array of Modelo, where Modelo is a class, it turns out I’m not getting access to the methods of this class, because the cast in the service is not being done properly, instead of the cast be made for a array of Modelo, is only an array of a normal javascript object, but typed with Modelo.

The http injected is from Angular2.

Follow the code with the classes mentioned:

I have the following class TypeScript, representing a model (Domain):

export class Modelo{
  id: number;
  type: string;
  size: number;

  constructor() {

  }

  public allowSize(): boolean {
    return this.type != null && (this.type.toLowerCase() == 'size');
  }

}

And the following service:

@Injectable()
export class ModeloService {

  constructor(private http: Http) {
  }

  getAll(): Observable<Modelo[]> {
    return this.http.get(myEnvironment.MODELO_SERVICE_PATH)
      .map(res => <Modelo[]> res.json());
  }

}

When trying to use this method allowSize(), I get the following error: ERROR TypeError: modelo.allowSize is not a function

modeloService.getAll()
  .subscribe(array=> array.forEach(modelo => console.log(modelo.allowSize())),
    error => console.log(error));

When printing modelo on the console, I do not receive an object Modelo, I only get a normal javascript object with key and values:

{id: 1;   type: 'size';   size: '10'}

The way I found to solve the problem was by creating the object, as follows:

getAll(): Observable<Modelo[]> {
  return this.http.get(myEnvironment.MODELO_SERVICE_PATH)
    .map(res => {

      return (<Modelo[]> res.json()).map(modelo => {
        let modeloToReturn = new Modelo();
        modeloToReturn.id = modelo.id;
        modeloToReturn.type= modelo.type;
        modeloToReturn.size = modelo.size;

        return modeloToReturn;
      })

    });
}

Solve, but causes another problem that is I have to keep evolving this service whenever I evolve my model, there is no way that this cast be done automatically?

2 answers

1

You can’t just make a cast of a Javascript result from an Ajax request to a Javascript/Typescript class instance. There are several techniques to do this and usually involve copying data. Unless you create an instance of the class (as you did yourself), you will have no method or property. It will remain as a simple Javascript object.

My suggestion is that you make one cast for a interface. An interface is purely a compile-time structure, i.e., it has zero runtime impact in Javascript. You can do something like this:

interface Modelo {
  id: number;
  type: string;
  size: number;
}

Using the above interface, it is necessary to move the logic of the method allowSize() for those who have the reference of that array.

For example, you can have the following code in a component, say model.componentts.

private modelos: Modelo[];

ngOnInit() {
    this.modelos = this.service.getAll();
}

get allowSize(index: number): boolean {
    return this.modelos[index].type != null &&
           this.modelos[index].type.toLowerCase() === 'size';
}

Then in your template template.component.html

<div *ngFor="let modelo of modelos; let i = index">
    <div *ngIf="allowSize(i)">Allow Size</div>
</div>
  • I didn’t understand why you cast for an interface and also didn’t understand this part: "This requires you to use a Typescript class that uses the data instance and perform operations with this data."

  • Could you explain it better? If you can implement it, thank you.

  • @Henriquesantiago improved the answer

  • ah, that I had already done. the only solution even to take advantage of object orientation is to do what I did in the same answer then? instance the Model in hand and popular the data?

  • @Henriquesantiago the way I suggested cast will work for the returning data. You will have a array of Modeloproperly populated. The only thing you need to do at hand is to validate the method allowSize. What you had done is different, you assigned each property individually.

  • What I meant to say, is that I’ve implemented it this way here in the project, I just didn’t put in the post.

Show 1 more comment

0


I decided to solve the problem by creating an unstable Model object, taking advantage of object orientation.

The way I put it in the post:

model.service.ts

getAll(): Observable<Modelo[]> {
  return this.http.get(myEnvironment.MODELO_SERVICE_PATH)
    .map(res => {

      return (<Modelo[]> res.json()).map(modelo => {
        let modeloToReturn = new Modelo();
        modeloToReturn.id = modelo.id;
        modeloToReturn.type= modelo.type;
        modeloToReturn.size = modelo.size;

        return modeloToReturn;
      })

    });
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.