将ajax结果分配给包含接口的方法

时间:2016-02-20 16:50:01

标签: casting typescript

我对Typescript很新,并且在我的代码工作方面遇到了一些问题。我有以下接口/类结构

interface IInterface {
  id : number;
  method() : string;
}

class IClass implements IInterface {
  id : number;
  method() : string { return "foo";}
}

现在我希望通过以下调用从Web服务获取一些数据

$.get("/some/url", (data : Array<IInterface>) => {
    for (var i = 0; i < data.length; i++) {
        console.log(data[i].id);
        console.log(data[i].method());
    }
});

虽然这可以很好地编写打字稿并且所有属性都设置得很好,但我得到一个运行时TypeError data[i].method is not a function

所以现在我的问题是:如何正确地转换/赋值(?),以便在生成的JavaScript中也可以使用这些方法?

UPDATE 根据要求:转发我从网络服务获得的数据。

data = [{id : 1}, {id : 2}, ...]  

当然,这是一个简化的例子,真正的类/接口有一些更多的属性(它们都被正确分配),但也只有一个方法(到目前为止,当我让它工作时,还会有更多的方法)。

1 个答案:

答案 0 :(得分:1)

这是将JSON对象转换为类实例的常见问题。这里讨论了一些提案:JSON to TypeScript class instance?

以下是我提出的进行反序列化的解决方案:

export class Helper
{
    public static DESCRIPTOR_SIGN = '$';

    private static m_entityModules = [];

    private static ReviveDateTime(key: any, value: any): any 
    {
        if (typeof value === 'string')
        {
            let a = /\/Date\((\d*)\)\//.exec(value);
            if (a)
            {
                return new Date(+a[1]);
            }
        }

        return value;
    }

    private static RessurectValue(json: any, environments: any[]): any
    {
        if(json == null)
        {
            return null;
        }
        else if(Helper.IsString(json))
        {
            return json;
        }
        else if(json instanceof Date)
        {
            return json;
        }
        else if(typeof json === 'object') 
        {
            return Helper.RessurectInternal(json, environments);
        } 
        else 
        {
            return json;
        }
    }

    private static RessurectInternal(json: any, environments: any[]): any 
    {
        var instance;

        if(!json[Helper.DESCRIPTOR_SIGN])
        {
            instance = {};
        }
        else
        {
            instance = Helper.CreateObject(json[Helper.DESCRIPTOR_SIGN]);

            if(Helper.IsUndefined(instance))
            {
                throw new Error('Unknown type to deserialize:' + json[Helper.DESCRIPTOR_SIGN]);
            }              
        }

        for(var prop in json) 
        {
            if(!json.hasOwnProperty(prop) || prop === Helper.DESCRIPTOR_SIGN) 
            {
                continue;
            }

            let val = json[prop];
            instance[prop] = Helper.Ressurect(val, environments);
        }

        return instance;
    }

    private static CreateObject(className: string, environments?: any[]): any
    {
        let instance: any;
        for(let e of environments)
        {
            var construct = e[className];

            if(!Helper.IsUndefined(construct))
            {
                instance = new construct(); 
                break;
            }
        }

        return instance;
    }

    private static IsNumber(val: any): boolean
    {
        return typeof val == 'number' || val instanceof Number;
    }

    private static IsUndefined(val: any): boolean
    {
        return typeof(val) === 'undefined';
    }

    private static IsString(val: any): boolean
    {
        return typeof val == 'string' || val instanceof String;
    }

    /**
     * Deserialize json object object into TypeScript one.
     * @param json json object that must have its class name in '$' field
     * @param environments list of modules containing all types that can be encountered during deserialization
     * @return deserialized typescript object of specified type  
     */
    public static Ressurect(val: any, environments: any[]): any 
    {
        if(val instanceof Array)
        {
            if(val.length == 0)
            {
                return val;
            }
            else 
            {
                let firstElement = val[0];
                if(typeof firstElement !== 'object')
                {
                    return val;
                }
                else
                {
                    let arr = [];
                    for (var i = 0; i < val.length; i++) 
                    {
                        var element = val[i];
                        arr.push(Helper.RessurectValue(element, environments));
                    }

                    return arr;
                }   
            }
        }
        else
        {
            return Helper.RessurectValue(val, environments);
        }
    }
}

以上的一些注意事项。它的工作原理是:

  1. 每种类型都有一个无参数构造函数可以反序列化。
  2. 每个JSON对象都包含字段&#39; $&#39;里面有班级名称。
  3. 使用样本。让我们假设你已经在一个名为&#39; Types&#39;的外部模式中定义了所有可序列化的类。然后反序列化你写的JSON对象:

    import * as types from './Types'
    
    //Some code to get jsonObj that has jsonObj.$ set to "RealObject" - a type from "Types" module
    
    let realObj = <types.RealObject>Helper.Resurrect(jsonObj, [types]);
    

    希望这有帮助。