如何使用JSON对象初始化TypeScript对象


197

我从AJAX调用REST服务器收到一个JSON对象。该对象具有与我的TypeScript类匹配的属性名称(这是此问题的后续内容)。

初始化它的最佳方法是什么?我认为行不通,因为类(&JSON对象)具有作为对象列表的成员和作为类的成员,而这些类具有作为列表和/或类的成员。

但是我更喜欢一种查找成员名称并在其间分配它们,创建列表并根据需要实例化类的方法,因此我不必为每个类中的每个成员编写明确的代码(有很多!)


1
您为什么又要问这个问题(因为我在另一个问题中提供的答案说这行不通,那是关于将属性复制到现有对象中)?
WiredPrairie 2014年


3
@WiredPrairie这个问题是不同的,它问我是否可以逐个遍历属性并将其分配。其他问题在问我是否可以投放。
David Thielen 2014年

1
@WiredPrairie续:如果您一直深入研究属性,直到仅了解原始类型,则可以对它们进行分配。
大卫·蒂伦

2
正如我建议的那样,它仍在复制所有值。TypeScript是JavaScript的基本设计,因此没有新的方法可以做到这一点。对于大型对象,您可能不想复制任何值,而只是“作用于”数据结构。
WiredPrairie 2014年

Answers:


188

这些是一些快速快照,它们显示了几种不同的方式。它们绝不是“完整的”,作为免责声明,我认为这样做不是一个好主意。代码也不是很干净,因为我只是很快地将它们键入在一起。

另请注意:可反序列化的类当然需要具有默认的构造函数,就像我知道任何反序列化的所有其他语言一样。当然,如果您调用不带参数的非默认构造函数,那么Javascript不会抱怨,但是该类最好为此做准备(此外,它实际上不是“打字方法”)。

选项#1:完全没有运行时信息

这种方法的问题主要是任何成员的名称都必须与其类匹配。这会自动将您限制为每个班级一名相同类型的成员,并破坏了一些良好实践的规则。我强烈建议您这样做,但请在此处列出,因为这是我编写此答案时的第一个“草稿”(这也是为什么名称为“ Foo”等的原因)。

module Environment {
    export class Sub {
        id: number;
    }

    export class Foo {
        baz: number;
        Sub: Sub;
    }
}

function deserialize(json, environment, clazz) {
    var instance = new clazz();
    for(var prop in json) {
        if(!json.hasOwnProperty(prop)) {
            continue;
        }

        if(typeof json[prop] === 'object') {
            instance[prop] = deserialize(json[prop], environment, environment[prop]);
        } else {
            instance[prop] = json[prop];
        }
    }

    return instance;
}

var json = {
    baz: 42,
    Sub: {
        id: 1337
    }
};

var instance = deserialize(json, Environment, Environment.Foo);
console.log(instance);

选项2:名称属性

为了摆脱选项1中的问题,我们需要掌握JSON对象中节点的类型的某种信息。问题在于,在Typescript中,这些都是编译时构造,我们在运行时需要它们-但是运行时对象只是在设置它们之前才意识到它们的属性。

一种方法是让类知道其名称。不过,您也需要在JSON中使用此属性。实际上,您需要在json中使用它:

module Environment {
    export class Member {
        private __name__ = "Member";
        id: number;
    }

    export class ExampleClass {
        private __name__ = "ExampleClass";

        mainId: number;
        firstMember: Member;
        secondMember: Member;
    }
}

function deserialize(json, environment) {
    var instance = new environment[json.__name__]();
    for(var prop in json) {
        if(!json.hasOwnProperty(prop)) {
            continue;
        }

        if(typeof json[prop] === 'object') {
            instance[prop] = deserialize(json[prop], environment);
        } else {
            instance[prop] = json[prop];
        }
    }

    return instance;
}

var json = {
    __name__: "ExampleClass",
    mainId: 42,
    firstMember: {
        __name__: "Member",
        id: 1337
    },
    secondMember: {
        __name__: "Member",
        id: -1
    }
};

var instance = deserialize(json, Environment);
console.log(instance);

选项3:明确说明成员类型

如上所述,类成员的类型信息在运行时不可用–除非我们使它可用。我们只需要对非原始成员执行此操作,我们很好:

interface Deserializable {
    getTypes(): Object;
}

class Member implements Deserializable {
    id: number;

    getTypes() {
        // since the only member, id, is primitive, we don't need to
        // return anything here
        return {};
    }
}

class ExampleClass implements Deserializable {
    mainId: number;
    firstMember: Member;
    secondMember: Member;

    getTypes() {
        return {
            // this is the duplication so that we have
            // run-time type information :/
            firstMember: Member,
            secondMember: Member
        };
    }
}

function deserialize(json, clazz) {
    var instance = new clazz(),
        types = instance.getTypes();

    for(var prop in json) {
        if(!json.hasOwnProperty(prop)) {
            continue;
        }

        if(typeof json[prop] === 'object') {
            instance[prop] = deserialize(json[prop], types[prop]);
        } else {
            instance[prop] = json[prop];
        }
    }

    return instance;
}

var json = {
    mainId: 42,
    firstMember: {
        id: 1337
    },
    secondMember: {
        id: -1
    }
};

var instance = deserialize(json, ExampleClass);
console.log(instance);

选项4:详细但整洁的方式

2016年1月3日更新:正如@GameAlchemist在评论中指出的(想法实现)中 Typescript 1.7开始,可以使用类/属性装饰器以更好的方式编写以下描述的解决方案。

序列化始终是一个问题,我认为最好的方法就是最短的方法。在所有选项中,这是我想要的,因为该类的作者完全控制了反序列化对象的状态。如果我不得不猜测,我会说所有其他选择迟早都会给您带来麻烦(除非Javascript提出了一种本机处理方式)。

的确,以下示例并未体现灵活性。它确实确实只是复制了类的结构。不过,您必须在这里记住的区别是,该类具有完全控制权,可以使用它想要控制整个类的状态的任何类型的JSON(您可以计算事物等)。

interface Serializable<T> {
    deserialize(input: Object): T;
}

class Member implements Serializable<Member> {
    id: number;

    deserialize(input) {
        this.id = input.id;
        return this;
    }
}

class ExampleClass implements Serializable<ExampleClass> {
    mainId: number;
    firstMember: Member;
    secondMember: Member;

    deserialize(input) {
        this.mainId = input.mainId;

        this.firstMember = new Member().deserialize(input.firstMember);
        this.secondMember = new Member().deserialize(input.secondMember);

        return this;
    }
}

var json = {
    mainId: 42,
    firstMember: {
        id: 1337
    },
    secondMember: {
        id: -1
    }
};

var instance = new ExampleClass().deserialize(json);
console.log(instance);

12
选项#4是我称之为合理的选择。您仍然需要编写反序列化代码,但是它在同一类中并且是完全可控的。如果您来自Java,那么这相当于必须编写equalstoString方法(仅通常使它们自动生成)。如果您愿意的话,为它编写一个生成器应该不会太难deserialize,但是它不能是运行时自动化。
IngoBürk2014年

2
@IngoBürk,我知道两年后我要问这个问题,但是它将如何处理对象数组?上面的示例代码适用于JSON对象。如何用于对象数组?
Pratik Gaikwad,2016年

2
旁注:自1.7(肯定比您的回答要晚)以来,打字稿提供了类/属性修饰符,该修饰符允许以更整洁的方式编写第4个解决方案。
GameAlchemist

1
我发现的最佳文档是StackOverflow答案:stackoverflow.com/a/29837695/856501 。我在我的一个项目中使用了装饰器,尽管我还需要其他一些功能,但我不得不说它们的作用像个魅力。
GameAlchemist

2
我还不会在生产项目中使用装饰器-请记住,它们仍然是实验功能。我不会在“实验”上建立真实的代码,因为就我们而言,它们可能会在下一个版本中消失,而您将不得不重写一堆代码,或者永远停留在旧的TS版本上。我的$ .02
RVP,2016年

35

您可以使用Object.assign我不知道何时添加它,我当前正在使用Typescript 2.0.2,这似乎是ES6功能。

client.fetch( '' ).then( response => {
        return response.json();
    } ).then( json => {
        let hal : HalJson = Object.assign( new HalJson(), json );
        log.debug( "json", hal );

这是 HalJson

export class HalJson {
    _links: HalLinks;
}

export class HalLinks implements Links {
}

export interface Links {
    readonly [text: string]: Link;
}

export interface Link {
    readonly href: URL;
}

这是铬所说的

HalJson {_links: Object}
_links
:
Object
public
:
Object
href
:
"http://localhost:9000/v0/public

所以你可以看到它没有递归分配


2
因此,基本上是这样的:Object.assign。那么为什么在这个答案之上有两个类似词典的答案呢?
phil294

18
@Blauhim因为Object.assign将无法递归工作,并且不会实例化正确的对象类型,而将值保留为Object实例。尽管可以完成琐碎的任务,但是复杂类型的序列化是不可能的。例如,如果类属性为自定义类类型,则JSON.parse+ Object.assign会将其实例化为Object。副作用包括缺少方法和访问器。
John Weisz

@JohnWeisz对象分配的顶级类确实具有正确的类型,而我在此提到了递归的内容……就是说,YMMV,这些可能会破坏交易。
xenoterracide

直接引出以下问题:“该类的成员是对象的列表,而成员是类,而那些类的成员是列表和/或类的成员,我宁愿使用一种查找成员的方法命名并分配它们,根据需要创建列表和实例化类,因此,我不必为每个类中的每个成员编写显式代码 -情况并非如此Object.assign,它仍然归结为通过嵌套嵌套实例化手。这种方法适用于非常简单的教程级对象,但不适用于实际用途。
约翰·魏茨,

@JohnWeisz可以肯定地回答了这个问题,因为它没有任何答案,对于某些用例来说似乎很简单。我敢肯定,它也可以与其他答案(例如反射)结合使用,以执行您想要的操作。我也写了一部分,以便以后记住。查看这些答案并使用和编写了功能更强大的库,似乎没有什么可用于“实际使用”。
xenoterracide

34

TLDR:TypedJSON(有效的概念证明)


这个问题复杂性的根源在于,我们需要在运行时使用仅在编译时存在的类型信息对JSON进行反序列化。这要求在运行时以某种方式提供类型信息。

幸运的是,可以使用装饰器ReflectDecorators以非常优雅和健壮的方式解决此问题:

  1. 在需要序列化的属性上使用属性装饰器来记录元数据信息并将该信息存储在某个地方,例如在类原型上
  2. 将此元数据信息提供给递归初始化程序(反序列化器)

 

记录类型信息

结合使用ReflectDecorators和属性装饰器,可以轻松记录有关属性的类型信息。此方法的基本实现为:

function JsonMember(target: any, propertyKey: string) {
    var metadataFieldKey = "__propertyTypes__";

    // Get the already recorded type-information from target, or create
    // empty object if this is the first property.
    var propertyTypes = target[metadataFieldKey] || (target[metadataFieldKey] = {});

    // Get the constructor reference of the current property.
    // This is provided by TypeScript, built-in (make sure to enable emit
    // decorator metadata).
    propertyTypes[propertyKey] = Reflect.getMetadata("design:type", target, propertyKey);
}

对于任何给定的属性,以上代码片段都将对该属性的构造函数的引用添加到__propertyTypes__类原型的hidden 属性上。例如:

class Language {
    @JsonMember // String
    name: string;

    @JsonMember// Number
    level: number;
}

class Person {
    @JsonMember // String
    name: string;

    @JsonMember// Language
    language: Language;
}

就是这样,我们在运行时拥有必需的类型信息,现在可以对其进行处理。

 

处理类型信息

我们首先需要Object使用JSON.parse- 获得一个实例,然后,我们可以遍历__propertyTypes__(收集到的)整个实例,并相应地实例化所需的属性。必须指定根对象的类型,以便解串器具有起点。

再次,这种方法的简单实现将是:

function deserialize<T>(jsonObject: any, Constructor: { new (): T }): T {
    if (!Constructor || !Constructor.prototype.__propertyTypes__ || !jsonObject || typeof jsonObject !== "object") {
        // No root-type with usable type-information is available.
        return jsonObject;
    }

    // Create an instance of root-type.
    var instance: any = new Constructor();

    // For each property marked with @JsonMember, do...
    Object.keys(Constructor.prototype.__propertyTypes__).forEach(propertyKey => {
        var PropertyType = Constructor.prototype.__propertyTypes__[propertyKey];

        // Deserialize recursively, treat property type as root-type.
        instance[propertyKey] = deserialize(jsonObject[propertyKey], PropertyType);
    });

    return instance;
}
var json = '{ "name": "John Doe", "language": { "name": "en", "level": 5 } }';
var person: Person = deserialize(JSON.parse(json), Person);

上面的想法有一个很大的优势,那就是按期望的类型(对于复杂/对象值)反序列化,而不是JSON中的反序列化。如果Person期望a,那么将Person创建一个实例。通过针对原始类型和数组采取一些其他安全措施,可以使此方法变得安全,可以抵御任何恶意JSON。

 

边缘案例

但是,如果你现在高兴的是,解决方案简单的,我有一些坏消息:有一个广阔的需要被照顾的边缘情况数。仅其中一些是:

  • 数组和数组元素(尤其是在嵌套数组中)
  • 多态性
  • 抽象类和接口
  • ...

如果您不想摆弄所有这些内容(我敢打赌您不愿意),我很高兴为您推荐一个使用这种方法的实验性概念验证版本,即TypedJSON,这是我创建的为了解决这个确切的问题,我每天都会面对自己的问题。

由于装饰器仍处于实验状态,因此我不建议将其用于生产用途,但到目前为止,它对我来说还是不错的。


TypedJSON效果很好;非常感谢您的参考。
尼尔

出色的工作,您已经为困扰我一段时间的问题提出了一个非常优雅的解决方案。我将密切关注您的项目!
约翰·斯特里克勒

12

我一直在用这个人来做这项工作:https : //github.com/weichx/cerialize

它非常简单但功能强大。它支持:

  • 整个对象树的序列化和反序列化。
  • 同一对象的持久性和瞬时性。
  • 挂钩自定义(反)序列化逻辑。
  • 它可以(反)序列化为现有实例(对于Angular来说很好)或生成新实例。
  • 等等

例:

class Tree {
  @deserialize public species : string; 
  @deserializeAs(Leaf) public leafs : Array<Leaf>;  //arrays do not need extra specifications, just a type.
  @deserializeAs(Bark, 'barkType') public bark : Bark;  //using custom type and custom key name
  @deserializeIndexable(Leaf) public leafMap : {[idx : string] : Leaf}; //use an object as a map
}

class Leaf {
  @deserialize public color : string;
  @deserialize public blooming : boolean;
  @deserializeAs(Date) public bloomedAt : Date;
}

class Bark {
  @deserialize roughness : number;
}

var json = {
  species: 'Oak',
  barkType: { roughness: 1 },
  leafs: [ {color: 'red', blooming: false, bloomedAt: 'Mon Dec 07 2015 11:48:20 GMT-0500 (EST)' } ],
  leafMap: { type1: { some leaf data }, type2: { some leaf data } }
}
var tree: Tree = Deserialize(json, Tree);

6

我创建了产生打字稿接口和一个运行时“型图”进行对抗的结果运行时类型检查的工具JSON.parsets.quicktype.io

例如,给定此JSON:

{
  "name": "David",
  "pets": [
    {
      "name": "Smoochie",
      "species": "rhino"
    }
  ]
}

quicktype产生以下TypeScript接口和类型映射:

export interface Person {
    name: string;
    pets: Pet[];
}

export interface Pet {
    name:    string;
    species: string;
}

const typeMap: any = {
    Person: {
        name: "string",
        pets: array(object("Pet")),
    },
    Pet: {
        name: "string",
        species: "string",
    },
};

然后我们JSON.parse对照类型图检查结果:

export function fromJson(json: string): Person {
    return cast(JSON.parse(json), object("Person"));
}

我遗漏了一些代码,但是您可以尝试使用quicktype获取详细信息。


1
经过大量的研究并尝试了几种解析技术后,我可以说这是一个很好的解决方案-主要是因为装饰器仍处于实验阶段。*原始链接对我来说是无效的;但是ts.quicktype.io可以工作。*将JSON转换为JSON Schema是一个很好的第一步。
LexieHankins '18

3

选项#5:使用Typescript构造函数和jQuery.extend

这似乎是最可维护的方法:添加一个将json结构作为参数的构造函数,并扩展json对象。这样,您可以将json结构解析为整个应用程序模型。

无需创建接口或在构造函数中列出属性。

export class Company
{
    Employees : Employee[];

    constructor( jsonData: any )
    {
        jQuery.extend( this, jsonData);

        // apply the same principle to linked objects:
        if ( jsonData.Employees )
            this.Employees = jQuery.map( jsonData.Employees , (emp) => {
                return new Employee ( emp );  });
    }

    calculateSalaries() : void { .... }
}

export class Employee
{
    name: string;
    salary: number;
    city: string;

    constructor( jsonData: any )
    {
        jQuery.extend( this, jsonData);

        // case where your object's property does not match the json's:
        this.city = jsonData.town;
    }
}

在您接收到公司来计算工资的ajax回调中:

onReceiveCompany( jsonCompany : any ) 
{
   let newCompany = new Company( jsonCompany );

   // call the methods on your newCompany object ...
   newCompany.calculateSalaries()
}

哪里$.extend来的?
whale_steward

@whale_steward我假设作者指的是jQuery库。在JavaScript世界中,“ $”通常是使用jQuery的人。
尼克·罗斯

如何导入呢?只在html头上包含它就足够了吗?
whale_steward

是的,我更新了答案以用jQuery替换$。在html头中导入jQuery.js,并在package.json,devDependencies部分中安装@ types / jquery并添加。
AnthonyBrenelière17年

1
请注意,在Javascript中,您应该执行Object.assign,这将删除对jQuery的依赖。
莱昂佩尔蒂埃

2

对于简单的对象,我喜欢这种方法:

class Person {
  constructor(
    public id: String, 
    public name: String, 
    public title: String) {};

  static deserialize(input:any): Person {
    return new Person(input.id, input.name, input.title);
  }
}

var person = Person.deserialize({id: 'P123', name: 'Bob', title: 'Mr'});

利用在构造函数中定义属性的能力,可以使其简洁。

这将为您提供一个类型化的对象(与使用Object.assign或某些变体的所有答案(为您提供一个对象)相对),并且不需要外部库或装饰器。


1

上面描述的第4个选项是一种简单而不错的方法,在必须处理类层次结构(例如,成员列表是任何子类的出现)的情况下,必须与第二个选项结合使用成员超类,例如,主管扩展成员或学生扩展成员。在这种情况下,您必须以json格式提供子类类型


1

JQuery .extend为您做到这一点:

var mytsobject = new mytsobject();

var newObj = {a:1,b:2};

$.extend(mytsobject, newObj); //mytsobject will now contain a & b

0

也许不是实际的,但是简单的解决方案:

interface Bar{
x:number;
y?:string; 
}

var baz:Bar = JSON.parse(jsonString);
alert(baz.y);

也为困难的依赖而工作!!!


9
这种方法实际上无法按预期工作。如果检查运行时结果,baz则将是类型,Object而不是类型Bar.。在这种简单情况下,因为Bar没有方法(仅是基本属性),它才有效。如果Bar使用类似的方法isEnabled(),则该方法将失败,因为该方法将不在序列化的JSON字符串中。
Todd

0

使用工厂的另一种选择

export class A {

    id: number;

    date: Date;

    bId: number;
    readonly b: B;
}

export class B {

    id: number;
}

export class AFactory {

    constructor(
        private readonly createB: BFactory
    ) { }

    create(data: any): A {

        const createB = this.createB.create;

        return Object.assign(new A(),
            data,
            {
                get b(): B {

                    return createB({ id: data.bId });
                },
                date: new Date(data.date)
            });
    }
}

export class BFactory {

    create(data: any): B {

        return Object.assign(new B(), data);
    }
}

https://github.com/MrAntix/ts-deserialize

这样使用

import { A, B, AFactory, BFactory } from "./deserialize";

// create a factory, simplified by DI
const aFactory = new AFactory(new BFactory());

// get an anon js object like you'd get from the http call
const data = { bId: 1, date: '2017-1-1' };

// create a real model from the anon js object
const a = aFactory.create(data);

// confirm instances e.g. dates are Dates 
console.log('a.date is instanceof Date', a.date instanceof Date);
console.log('a.b is instanceof B', a.b instanceof B);
  1. 使您的课程保持简单
  2. 注射可提供给工厂以提高灵活性

0

我为此找到的最好的是class-transformer。github.com/typestack/class-transformer

那就是你的用法:

某类:

export class Foo {

    name: string;

    @Type(() => Bar)
    bar: Bar;

    public someFunction = (test: string): boolean => {
        ...
    }
}


import { plainToClass } from 'class-transformer';

export class SomeService {

  anyFunction() {
u = plainToClass(Foo, JSONobj);
 }

如果使用@Type装饰器,则也会创建嵌套属性。


0

我个人更喜欢@IngoBürk的选项#3。而且我改进了他的代码,以支持复杂数据数组和原始数据数组。

interface IDeserializable {
  getTypes(): Object;
}

class Utility {
  static deserializeJson<T>(jsonObj: object, classType: any): T {
    let instanceObj = new classType();
    let types: IDeserializable;
    if (instanceObj && instanceObj.getTypes) {
      types = instanceObj.getTypes();
    }

    for (var prop in jsonObj) {
      if (!(prop in instanceObj)) {
        continue;
      }

      let jsonProp = jsonObj[prop];
      if (this.isObject(jsonProp)) {
        instanceObj[prop] =
          types && types[prop]
            ? this.deserializeJson(jsonProp, types[prop])
            : jsonProp;
      } else if (this.isArray(jsonProp)) {
        instanceObj[prop] = [];
        for (let index = 0; index < jsonProp.length; index++) {
          const elem = jsonProp[index];
          if (this.isObject(elem) && types && types[prop]) {
            instanceObj[prop].push(this.deserializeJson(elem, types[prop]));
          } else {
            instanceObj[prop].push(elem);
          }
        }
      } else {
        instanceObj[prop] = jsonProp;
      }
    }

    return instanceObj;
  }

  //#region ### get types ###
  /**
   * check type of value be string
   * @param {*} value
   */
  static isString(value: any) {
    return typeof value === "string" || value instanceof String;
  }

  /**
   * check type of value be array
   * @param {*} value
   */
  static isNumber(value: any) {
    return typeof value === "number" && isFinite(value);
  }

  /**
   * check type of value be array
   * @param {*} value
   */
  static isArray(value: any) {
    return value && typeof value === "object" && value.constructor === Array;
  }

  /**
   * check type of value be object
   * @param {*} value
   */
  static isObject(value: any) {
    return value && typeof value === "object" && value.constructor === Object;
  }

  /**
   * check type of value be boolean
   * @param {*} value
   */
  static isBoolean(value: any) {
    return typeof value === "boolean";
  }
  //#endregion
}

// #region ### Models ###
class Hotel implements IDeserializable {
  id: number = 0;
  name: string = "";
  address: string = "";
  city: City = new City(); // complex data
  roomTypes: Array<RoomType> = []; // array of complex data
  facilities: Array<string> = []; // array of primitive data

  // getter example
  get nameAndAddress() {
    return `${this.name} ${this.address}`;
  }

  // function example
  checkRoom() {
    return true;
  }

  // this function will be use for getting run-time type information
  getTypes() {
    return {
      city: City,
      roomTypes: RoomType
    };
  }
}

class RoomType implements IDeserializable {
  id: number = 0;
  name: string = "";
  roomPrices: Array<RoomPrice> = [];

  // getter example
  get totalPrice() {
    return this.roomPrices.map(x => x.price).reduce((a, b) => a + b, 0);
  }

  getTypes() {
    return {
      roomPrices: RoomPrice
    };
  }
}

class RoomPrice {
  price: number = 0;
  date: string = "";
}

class City {
  id: number = 0;
  name: string = "";
}
// #endregion

// #region ### test code ###
var jsonObj = {
  id: 1,
  name: "hotel1",
  address: "address1",
  city: {
    id: 1,
    name: "city1"
  },
  roomTypes: [
    {
      id: 1,
      name: "single",
      roomPrices: [
        {
          price: 1000,
          date: "2020-02-20"
        },
        {
          price: 1500,
          date: "2020-02-21"
        }
      ]
    },
    {
      id: 2,
      name: "double",
      roomPrices: [
        {
          price: 2000,
          date: "2020-02-20"
        },
        {
          price: 2500,
          date: "2020-02-21"
        }
      ]
    }
  ],
  facilities: ["facility1", "facility2"]
};

var hotelInstance = Utility.deserializeJson<Hotel>(jsonObj, Hotel);

console.log(hotelInstance.city.name);
console.log(hotelInstance.nameAndAddress); // getter
console.log(hotelInstance.checkRoom()); // function
console.log(hotelInstance.roomTypes[0].totalPrice); // getter
// #endregion

-1

你可以像下面这样

export interface Instance {
  id?:string;
  name?:string;
  type:string;
}

var instance: Instance = <Instance>({
      id: null,
      name: '',
      type: ''
    });

这实际上不会产生您期望的对象类型的运行时实例。当您的类型仅具有基本属性时,它将似乎起作用,但是当类型具有方法时,它将失败。接口定义在运行时也不可用(仅在构建时)。
Todd

-1
**model.ts**
export class Item {
    private key: JSON;
    constructor(jsonItem: any) {
        this.key = jsonItem;
    }
}

**service.ts**
import { Item } from '../model/items';

export class ItemService {
    items: Item;
    constructor() {
        this.items = new Item({
            'logo': 'Logo',
            'home': 'Home',
            'about': 'About',
            'contact': 'Contact',
        });
    }
    getItems(): Item {
        return this.items;
    }
}

调用类似下面的示例的内容:
user8390810 '17

<a class="navbar-brand" href="#"> {{keyItems.key.logo}} </a>
user8390810

这似乎没有“根据需要实例化类”。
LexieHankins '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.