【问题标题】:Assign ajax result to interface inclusive methods将 ajax 结果分配给接口包含方法
【发布时间】:2016-02-20 16:50:01
【问题描述】:

我对 Typescript 还是很陌生,在让我的代码正常工作时遇到了一些问题。我有以下接口/类结构

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

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

现在我想通过以下调用从网络服务获取一些数据

$.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 中使用?

更新 根据要求:我从网络服务获得的数据转储。

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

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

【问题讨论】:

  • 你缺少一个括号:console.log(data[i].method());
  • @FlorianTopf 抱歉打错了。括号包含在原始代码中(没有它,它将无法编译)。我更新了我的问题。
  • 你能转储整个data[i]对象吗?
  • 我不确定你所说的转储是什么意思。我从 web 服务收到的数据 [i] 基本上只是一个带有一堆属性的普通对象。请看我的更新
  • 好的,那么您需要映射结果并创建新类:data.map((d) =&gt; return new IClass(d.id)). 类似的东西。但是你需要在IClass中引入一个构造函数

标签: casting typescript


【解决方案1】:

问题是您收到的是符合接口的对象,但它们内部没有method 属性。

您需要做的是,您需要在响应处理程序中从类型IClass 创建新对象,以扩展data 内的对象:

$.get("/some/url", (data: Array<IInterface>) => {
    return data.map((d) => return new IClass(d.id));
});

【讨论】:

    【解决方案2】:

    这是将 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 对象都包含字段“$”及其类名。

    使用示例。假设您已经在一种称为“类型”的外部模式中定义了所有可序列化的类。然后反序列化您编写的 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]);
    

    希望这会有所帮助。

    【讨论】:

    • 不错的答案,但目前我更喜欢更简单的东西。还是谢谢。
    猜你喜欢
    • 1970-01-01
    • 2018-12-07
    • 2015-11-05
    • 1970-01-01
    • 2019-06-26
    • 1970-01-01
    • 2019-02-15
    • 2017-04-12
    • 2015-04-07
    相关资源
    最近更新 更多