Promise not returning a valid class instance [dupl

2020-04-21 06:17发布

问题:

I've just started learning Typescript and I'm already lost in something that sounds really strange for a C# developer.

Summary: Promise<WsIdSessionResponse> returns a variable that has same fields of WsIdSessionResponse class but it's not a valid WsIdSessionResponse instance.

Long story
I have a service like this (I've omitted something useless for the problem) consuming a JSON webservice not written by me:

export class WsIdSessionService {
    constructor(private http: HttpClient) { }

    doLoginAsync(user: string, pwd: string): Promise<WsIdSessionResponse> {
        let params = new HttpParams();
        params = params.append('username', user);
        params = params.append('password', pwd);
        return this.http.get<WsIdSessionResponse>(this.apiUrl, {params: params})
            .toPromise());
    };

WsIdSessionResponse class is like this

export class WsIdSessionResponse {
    public status: number;
    public username: string;

    public isOk(): boolean {
        return this.status == 1;
    }
}

Problem comes when I retrieve data from WsIdSessionService:

var idSvc = this.wsIdSession.doLoginAsync(user, pwd);
var t = idSvc.then(info => {
    if (t.isOk()) {
      // Do something here
    }
}

When I execute t.isOk() I get an error telling me that isOk() is not a function!
What?!? Not a function? Yes it is, I have that function in my class!

After wasting a huge amount of time, I finally thought about trying this code

var idSvc = this.wsIdSession.doLoginAsync(user, pwd);
var t = idSvc.then(info => {
    console.warn(`info is valid: ${info instanceof WsIdSessionResponse}`);
}

Here I get a false as result: so returned variable has same fields of the class I need but it's not a real instance of the class and that's the reason isOk() function is not valid!
But how is this possible? I mean, http.get<WsIdSessionResponse> should return a valid instance of the WsIdSessionResponse or eventually an error... am I wrong?

Just to provide complete infos: http.get<WsIdSessionResponse> gets data from a url returning a plain JSON string.

Is this the expected behaviour or am I doing something wrong?

回答1:

<WsIdSessionResponse> doesn't make the object an instance of WsIdSessionResponse. It cheats typing system to think that it is an instance and suppresses type errors. TypeScript is JavaScript with type safety, and it is just JavaScript when it's compiled.

Unless an instance of WsIdSessionResponse is created explicitly with new, the object will stay Object, with no isOk method.

The way it's supposed to work is:

interface IWsIdSessionResponse {
    status: number;
    username: string;
}

class WsIdSessionResponse implements IWsIdSessionResponse {
    public status: number;
    public username: string;

    public isOk(): boolean {
        return this.status == 1;
    }
}

...

doLoginAsync(user: string, pwd: string): Promise<WsIdSessionResponse> {
        ...
        return this.http.get<IWsIdSessionResponse>(this.apiUrl, {params: params})
            .map(plainResponseObj => Object.assign(new WsIdSessionResponse, plainResponseObj))
            .toPromise());
    };