【问题标题】:Promise not returning a valid class instance [duplicate]承诺不返回有效的类实例[重复]
【发布时间】:2017-09-18 06:46:08
【问题描述】:

我刚刚开始学习 Typescript,我已经迷失在一些对于 C# 开发人员来说听起来很奇怪的东西。

总结: Promise<WsIdSessionResponse> 返回一个与WsIdSessionResponse 类具有相同字段的变量,但它不是有效的WsIdSessionResponse 实例。

说来话长
我有这样的服务(我省略了对问题无用的东西)使用不是我编写的 JSON 网络服务:

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类是这样的

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

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

当我从WsIdSessionService 检索数据时出现问题:

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

当我执行t.isOk() 时,我收到一条错误消息,告诉我isOk() 不是函数!
什么?!?不是函数?是的,我的课堂上有这个功能!

在浪费了大量时间之后,我终于想试试这个代码

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

在这里我得到一个false 结果:所以返回的变量具有我需要的类的相同字段,但它不是该类的真实实例,这就是isOk() 函数无效的原因!
但这怎么可能?我的意思是,http.get&lt;WsIdSessionResponse&gt; 应该返回一个有效的WsIdSessionResponse 实例,或者最终是一个错误......我错了吗?

只是为了提供完整的信息:http.get&lt;WsIdSessionResponse&gt; 从返回纯 JSON 字符串的 url 获取数据。

这是预期的行为还是我做错了什么?

【问题讨论】:

  • 看起来用户在使用 C# 背景时遇到了完全相同的问题。 TS 只是编译时出现类型错误的 JS。它不会对 JS 不期望的对象进行魔术变换。

标签: angular typescript


【解决方案1】:

&lt;WsIdSessionResponse&gt; 不会使对象成为WsIdSessionResponse 的实例。它欺骗打字系统认为它是一个实例并抑制类型错误。 TypeScript 是具有类型安全性的 JavaScript,编译时只是 JavaScript。

除非WsIdSessionResponse 的实例是用new 显式创建的,否则该对象将保持Object,没有isOk 方法。

它应该工作的方式是:

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());
    };

【讨论】:

  • 谢谢,我已经通过手动创建实例解决了,但方式不那么优雅和快速。 JS 你说得对,我只需要学习与 C# 的区别,我相信我会很头疼。
  • 当我使用.map(resp=&gt; 时,我收到一条错误消息,指出Property map doesn't exist on type 'Observable&lt;IWsIdSessionResponse&gt;'。即使删除类型并使用普通的http.get,我仍然会收到与Observable&lt;Object&gt;类型相同的错误
  • 不客气。 Object.assign 对现有类有点破解。这里的正确模式是具有自填充类构造函数(参见Item 此处,stackoverflow.com/a/45847569/3731501)。 doesn't exist on type 'Observable 是 Angular 4 中 observables 的常见问题。对您正在使用的每个运算符使用 import 'rxjs/add/operator/map' 等。
  • 很遗憾,没有太多时间,我还有很长的路要走,但我认为这可能是未来,我最好学习一下!非常感谢您的支持!
猜你喜欢
  • 2016-12-05
  • 2015-11-04
  • 2016-10-20
  • 2018-06-03
  • 2015-02-13
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多