打字稿&角度2反射

时间:2016-04-15 02:09:48

标签: javascript typescript angular

虽然这个主题已在其他帖子中讨论过:

Dynamically loading a typescript class (reflection for typescript)

我无法找到具体问题的答案。所以,请原谅我,如果这是重复的。

我正在尝试在Angular 2中创建一个非常简单的指令(使用Typescript),它允许动态添加或删除由Type表示的一组控件。例如,如果类型为:

class Stone{
  constructor(
  public nameOfStone?: string,
  public typeOfStone?: string
  ){}
}
用户界面就像这样:

Screenshot 1

我能够使用特定类型(例如:Stone)。但是,鉴于该指令的目的只是添加这个动态添加/删除功能,我觉得参数化要创建的类型并将其用于不同的类型定义是有意义的。我在Component类中尝试过类似的东西:

import {Component} from 'angular2/core';
import {NgForm}    from 'angular2/common';
import {ControlGroup, Control, FormBuilder, FORM_DIRECTIVES} from    'angular2/common'
@Component({
  selector: 'stone-details',
  templateUrl: '../stones/stone-details.component.html',
  directives: [FORM_DIRECTIVES]
})
export class StoneComponent {
  type = 'Stone';
  Stones = new Array<Stone>();

  addBtnClicked(){
    let Stone = Object.create(window['Stone'].prototype);
    //let Stone = new Stone('', '');
    this.Stones.push(Stone);
  }
  removeBtnClicked(index: number){
    if(index >= this.Stones.length){
      alert('Not a valid index');
    }else if(confirm('Remove this Stone?')){
      this.Stones.splice(index, 1);
    }
  }
}

class Stone{
  constructor(
   public nameOfDeity?: string,
   public typeOfDeity?: string
  ){}
}

当我使用注释行时 let Stone = new Stone('', ''); 组件工作完美,但如果我使用 let Stone = Object.create(window['Stone'].prototype); 它似乎不起作用,我看到的错误是 angular2.dev.js:23941 ORIGINAL EXCEPTION: TypeError: Cannot read property 'prototype' of undefined

我最初认为导出Stone类会有所帮助,但没有一个疯狂的变体(导出类,尝试将类称为窗口['StoneComponent']。export_1 ['Stone'])帮助。我知道组件在窗口组件下不能直接看到,但我不确定我缺少什么。有没有另一种方法可以做到这一点?我错过了什么吗?请指教。

P.S:我正在使用最新版本的Angular 2和Typescript(我在几天后开始使用这个应用程序)。

2 个答案:

答案 0 :(得分:1)

代码的问题是定义顺序。

具体来说,类定义 function 定义一样被提升。棘手的部分是类型 Stone被提升,这是完全有效的,但 Stone(构造函数)不是。

要解决此问题,只需将Stone的定义移到组件上方或将其提取到单独的模块中并导入它。

不要 尝试将其推送到全局变量,例如window。这是一种非常糟糕的做法,会比人们想象的更快地导致错误和名称冲突。它也失去了模块的好处。

简而言之,您需要的是

class Stone {
  constructor(
    readonly nameOfDeity?: string,
    readonly typeOfDeity?: string
  ) {}
}

export class StoneComponent {
  kind = 'Stone';
  stones: Stone[] = [];

  addBtnClicked() {
    const stone = new Stone();
    this.stones.push(stone);
  }
  removeBtnClicked(index: number) {
    if (index >= this.stones.length) {
      alert('Not a valid index');
    } else if (confirm('Remove this Stone?')){
      this.stones.splice(index, 1);
    }
  }
}

<强>更新 因为在原始问题中,您声明这将是一个通用组件,您将拥有多个类,其中实际类由组件类的kind属性选择。您可能需要考虑以下模式。

<强>组件场-kinds.ts

export class Stone { ... }

export class Widget { ... }

export class Gizmo { ... }

<强>仿制component.ts

import * as kinds from './component-field-kinds';

type Kind = keyof typeof kinds;

export class GenericComponent {
  @Input() kind: Kind;

  values: typeof kinds[Kind][] = [];

  addBtnClicked() {
    const value = new kinds[this.kind]();
    this.values.push(value);
}

注意,对于它的价值,JavaScript,因此TypeScript没有动态类加载器这样的东西。这就是语言一直在运作的方式,整个结构都是一流的。

这不是Java。

答案 1 :(得分:0)

由于class是简单函数,您可以使用new func()创建实例,但仍需要从外部代码传递func

我想最有效的解决方案如下:

export class StoneComponent<T> {
  addBtnClicked(){
    let item:T = <T>{}
    this.items.push(item);
  }
}
只要对象具有相同的属性集,

类型就会匹配。