简体   繁体   中英

Typescript: Cast type in subscribe or in map

I receive a json from the backend which contains an array of client object: Here is the client class:

export class Client {
    private id:number;
    private firstname: String;
    private lastname: String;
    private phone:String;
    private address:String;
    private country:String;
    private Security_No:String;
}

I am looking for easiest way to cast the received json to a Clients[] . currently i store the json in an attribute, and later i go throw it and extract data fram it. but it seems that, there should be an easier way?

populateClientData() {
    this._httpClientService.getAllClients().subscribe((res)=>this.data=res.json()))
}

You can not cast json data (that is, js objects) into classes.
Well, you can, but then you don't really have instances of the class but objects that satisfy the class interface.

Simple example:

class Point {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

let a = {
    x: 5,
    y: 5
} as Point;
console.log(a); // Object {x: 5, y: 5}

let b = new Point(5, 5);
console.log(b); // Point {x: 5, y: 5}

The compiler won't complain about a not being an instance of Point because it satisfies the Point interface, so these are valid:

function log(point: Point) {
    console.log(`(${ point.x }, ${ point.y })`);
}

log(a); // fine
log(b); // fine

( code in playground )

It works this way because :

One of TypeScript's core principles is that type-checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping”. In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.

More on duck typing .

As for you specific problem, you can use your class as an interface or just make it into an interface:

interface Client {
    id:number;
    firstname: String;
    lastname: String;
    phone:String;
    address:String;
    country:String;
    Security_No:String;
}

And then (in both cases):

this._httpClientService.getAllClients().subscribe((res) => {
    this.data = res.json() as Client[]
}));

But if you'll use your class (and not the interface) then the properties must be public and not private.

If you wish to use your class as a class and not interface then casting won't do, you'll need to:

this._httpClientService.getAllClients().subscribe((res) => {
    this.data = res.json().map(item => new Client(data));
}));

And you'll need to have a constructor for Client which accepts the interface and assigns the values to its members.

In my app, I have a user object that has many fields and a number of arrays to store data so it's a complex object. In the map operator, I can cast the response.json() to that value like this:

return this.http.get(this.constants.userUrl + userId, { headers: headers })
      .map((response: Response) => <User>response.json())
      .catch(this.handleError);
  }

The subscribe is handled the same way:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM