我可以在函数中创建一个TypeScript类并引用它的参数吗?

时间:2014-07-07 21:35:15

标签: angularjs typescript

E.g。在angularJS中,我可以使用以下结构:

myApp.factory('MyFactory', function(injectable) {
    return function(param) {
        this.saySomething = function() {
            alert("Param=" + param + " injectable=" +injectable);
        }
    };
});

以后可以这样使用:

function(MyFactory) {
    new MyFactory().saySomething();
}

当调用传递给方法factory的函数时,参数injectable被关在笼子中,并且可以进一步用于MyFactory的新实例,而无需再次指定该参数。

现在我想使用TypeScript,显然我想指定我的MyFactory是新的,并且有一个函数saySomething。我怎么能优雅地做到这一点?

我可以这样写:

class MyFactory {
    constructor(private injectable, private param) {}
    saySomething() {
        alert(...);
    }
}
myApp.factory('myFactory', function(injectable) {
    return function(param) {
        return new MyFactory(injectable, param);
    }
});

但这改变了API:

function(myFactory) {
    myFactory().saySomething();
}

我想知道它是否会更优雅,因为我喜欢" new"很清楚地表明创建了一个新的唯一对象,这个对象创建是工厂的整个目的。

3 个答案:

答案 0 :(得分:1)

**编辑:TypeScript> = 1.6支持class expressions,您现在可以编写如下内容:

myApp.factory(injectable: SomeService) {
  class TodoItem {
    ...
  }
}

**原始答案:

我遇到了同样的问题:使用AngularJS和ES5,我喜欢依赖注入而不是污染构造函数,并且能够使用new关键字。

使用ES6,您可以将一个类包装在一个函数中,TypeScript尚不支持它(参见https://github.com/Microsoft/TypeScript/issues/307)。

我在这里做的事情(MyFactory现在是来自todo app的TodoItem类更具相关性):

class TodoItem {
  title: string;
  completed: boolean;
  date: Date;

  constructor(private injectable: SomeService) { }

  doSomething() {
    alert(this.injectable);
  }
}

class TodoItemFactory() {
  constructor(private injectable: SomeService) { }

  create(): TodoItem {
    return new TodoItem(this.injectable);
  }

  // JSON from the server
  createFromJson(data: any): TodoItem {
    var todoItem = new TodoItem(this.injectable);
    todoItem.title = data.title;
    todoItem.completed = data.completed;
    todoItem.date = data.date;
    return todoItem;
  }
}

// In ES5: myApp.factory('TodoItem', function(injectable) { ... });
myApp.service('TodoItemFactory', TodoItemFactory);


class TodosCtrl {
  // In ES5: myApp.controller('TodosCtrl', function(TodoItem) { ... });
  constructor(private todoItemFactory: TodoItemFactory) { }

  doSomething() {
    // In ES5: var todoItem1 = new TodoItem();
    var todoItem1 = this.todoItemFactory.create();

    // In ES5: var todoItem2 = TodoItem.createFromJson(...)
    var todoItem2 = this.todoItemFactory.createFromJson(
      {title: "Meet with Alex", completed: false}
    );
  }
}

这不如ES5和函数优雅(并且不使用TypeScript的类是不行): - /

我想写的是:

@Factory
@InjectServices(injectable: SomeService, ...)
class TodoItem {
  title: string;
  completed: boolean;
  date: Date;

  // No DI pollution
  constructor() { }

  saySomething() {
    alert(this.injectable);
  }

  static createFromJson(data: string): TodoItem {
    ...
  }
}

@Controller
@InjectFactories(TodoItem: TodoItem, ...)
class TodosCtrl {
  constructor() { }

  doSomething() {
    var todoItem1 = new TodoItem();

    var todoItem2 = TodoItem.createFromJson({title: "Meet with Alex"});
  }
}

或使用功能:

myApp.factory(injectable: SomeService) {
  class TodoItem {
    title: string;
    completed: boolean;
    date: Date;

    // No constructor pollution
    constructor() { }

    saySomething() {
      alert(injectable);
    }

    static createFromJson(data: string): TodoItem {
      ...
    }
  }
}

myApp.controller(TodoItem: TodoItem) {
  class TodosCtrl {
    constructor() { }

    doSomething() {
      var todoItem1 = new TodoItem();

      var todoItem2 = TodoItem.createFromJson({title: "Meet with Alex"});
    }
  }
}

答案 1 :(得分:0)

  

我可以写这样的东西

这就是我的工作

  

我可以在函数

中创建TypeScript类吗?

不需要位于文件的顶层或模块中。仅供参考,如果能够在函数内创建它,信息将被锁定在该函数内,并且至少类型信息将是无用的。

答案 2 :(得分:0)

实例化MyFactory的多个实例的原因是什么?您是否希望将工厂的单个实例注入到相关代码中?

我认为使用你提供的类声明实际上会在注入后显示:

function(myFactory) {
    myFactory.saySomething();
}

如果你真的需要将构造函数传递给你的依赖代码,那么我认为你将不得不抛弃TypeScript类,因为它们不能在函数内部定义,这意味着你无法创建一个关注注入此函数的变量。

您始终可以选择仅使用TypeScript中的函数而不是类。仍然可以获得强大的输入效果,并可以在其上调用“新”,因为它在一天结束时仍然是.js功能。这是一个稍微更多的TypeScriptiffied版本:

myApp.factory('MyFactory', (injectable: ng.SomeService) => {

    return (param: string) => {

        return {
            saySomething: () {
                alert("Param=" + param + " injectable=" +injectable);
            }
        };
    };
});