【问题标题】:Runtime Error while Casting an object投射对象时出现运行时错误
【发布时间】:2019-01-03 20:05:53
【问题描述】:

我正在处理一个Typescript 项目,虽然代码编译得很好,并且在所有概念的理论领域中代码应该可以工作,但它在运行时不起作用。

我已经缩小了问题的范围,即TypeScript在编译后被转换为JavaScript。这意味着没有定义的类和变量类型(管道类型也称为解释语言)。

现在我需要帮助的地方是让它工作。下面是类结构:

基类

当我从 API 获得响应时,我将其转换为基类类型

class BaseCollectionTypeResponseModel<TObject>{

    protected responseData: Array<TObject>;

    protected pagination: PaginationResponseModel;

}

PaginationResponseModel 定义如下:

class PaginationResponseModel {
    protected totalItems: number;

    protected totalPages: number;

    protected currentPage: number;

    protected itemCount: number;

}

现在我定义了一个interface,它有一个函数ConvertViaAdapter(),如下所示:

interface IConvertable{
    ConvertViaAdapter();
}

实现该接口的示例类如下:

class PlatformResponseModel implements IConvertable{

    protected status: number;

    protected name: string;

    protected platformid: string;

    protected tags: string[];

    protected type: string;

    protected version: string;

    protected description: string;

    ConvertViaAdapter(): PlatformModel {
        return Object.assign(new PlatformModel(), this)
    }
}

现在我正在创建利用基类功能提供应用程序特定功能的子类。

子类:

例如,分页子类如下所示: 类 PaginationModel 扩展 APIResponses.PaginationResponseModel{

    get TotalItems(): number{
        return this.totalItems
    }

    get TotalPages(): number{
        return this.totalPages
    }

    get CurrentPage(): number{
        return this.currentPage
    }

    get ItemCount(): number{
        return this.itemCount
    }
}

现在事情变得棘手了:

我已经扩展了PlatformResponseModel,如下所示:

class PlatformFunctionalModel extends PlatformResponseModel{

    get Name(): string{
        return this.name
    }

    get IsActive(): boolean{
                if (this.type == 0)
            return True;
                return False;
    }
}

我还使用下面的泛型扩展了 BaseCollectionTypeModel:

class CollectionTypeBaseModel<TObject extends YObject, YObject extends IConvertable> extends BaseCollectionTypeResponseModel<YObject>{

    private _responseData: Array<TObject> = []
    get ResponseData(): Array<TObject>{
        if (this._responseData == null || this._responseData.length < 1){
            this.responseData.forEach((data)=>{
                this._responseData.push(data.ConvertViaAdapter());
            });
        }
        return this.responseData;
    }
    set ResponseData(data: Array<TObject>){
        this.responseData = data 
        this._responseData = data 
    }

    get Pagination(): PaginationModel{
        return Object.assign(new PaginationModel(), this.pagination)   
    }
}

问题出在上面类中的代码行this.responseData.forEach(),我得到错误:

对象类型没有ConvertViaAdapter()的方法。

现在它应该可以工作了,因为当TObject 扩展IConvertable 接口时,TObject 类型的列表项将定义并实现函数,否则代码将无法编译。我需要帮助。

JSON 示例

{"responseData":[{"status":2,"name":"HelloSample","platformid":"A1B2C3","tags":["hello","sample"],"type":"delta","version":"v1.0","description":"Just a sample"}],"pagination":{"totalItems":10,"totalPages":5,"currentPage":1,"itemCount":2}}

起始码:

var objectData = JSON.parse(jsonData);
var myCastedData = Object.assign(new CollectionTypeBaseModel<PlatformFunctionalModel, PlatformResponseModel>(), objectData)

【问题讨论】:

  • 我强烈建议您将数据和操作分开。 Classes + JSON 会导致悲伤,有时会导致精神错乱,而你却一无所获。此外,您似乎对鸭子打字与解释与编译感到困惑,而这些都与您的问题无关。您的问题是使用类作为类型注释并假设会自动应用转换。即使在具有完全具体化类型系统的语言(例如 C#)中,也需要反射序列化系统来处理 JSON、XML 和其他文本数据
  • @AluanHaddad 是的,我知道C# 处理序列化和反序列化的方式。我正在研究如何在 TypeScipt 中使用DataContract JSON Serialization and Deserialization。遇到了一个叫做TypedJSON的东西。问题是这段代码。它在 C# 中效果很好我已经测试了代码的流程,然后再把问题放在这里。
  • 不要走那条路。你会后悔的,或者充其量,你不会知道自己有多悲惨:p。这种方法不适用于 JavaScript 或 TypeScript。如果您认为 TypeScript 编译为纯 JavaScript 是一个弱点,那么您将永远不会很好地使用它。 TypeScript 仅用于工具,它非常适合。
  • @AluanHaddad 哦。有没有更好的方法可以告诉我我可以塑造代码,我有一个服务库,可以进行 API 调用,然后需要将响应从 JSON 对象转换为 BaseCollectionTypeResponseModel&lt;PlatformResponseModel&gt;,然后再转换为 CollectionTypeBaseModel&lt;PlatformFunctionalModel, PlatformResponseModel&gt;
  • 我建议你放弃这种方法。使用interfaces 声明 API 响应的形状,并使用外部函数或服务类对它们进行操作,这些函数或服务类采用普通对象和数组并返回普通对象和数组。使用非类类型键入这些方法并使用静态鸭子类型。

标签: typescript generics interface casting


【解决方案1】:

我认为示例 JSON 在 responseData 周围缺少一个数组。

由于(您似乎已经意识到)responseData 对象是纯 JavaScript 对象而不是 PlatformResponseModel 对象,因此您必须想出另一种方法将转换函数传递给 CollectionTypeBaseModel。例如,您可以将其作为构造函数参数传递:

class CollectionTypeBaseModel<TObject extends YObject, YObject extends IConvertable> extends BaseCollectionTypeResponseModel<YObject>{
    constructor(private converter: (obj: TObject) => any) { super(); }

    private _responseData: Array<TObject> = []
    get ResponseData(): Array<TObject>{
        if (this._responseData == null || this._responseData.length < 1){
            this.responseData.forEach((data)=>{
                this._responseData.push(this.converter(data));
            });
        }
        return this.responseData;
    }

    // ...
}

objectData = JSON.parse(jsonData);
var myCastedData = Object.assign(
    new CollectionTypeBaseModel<PlatformFunctionalModel, PlatformResponseModel>(
        (data) => Object.assign(new PlatformModel(), data)),
    objectData)

【讨论】:

  • 您对示例 JSON 中缺少的数组类型是正确的。请随时编辑问题。到目前为止,我远离我的系统。我会测试你的代码并尽快恢复。谢谢
猜你喜欢
  • 2015-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 2014-03-07
  • 2014-10-30
  • 1970-01-01
相关资源
最近更新 更多