Typescript + Angular "controller as" Sidewaffle 模板开箱即用

Typescript + Angular "controller as" Sidewaffle template doesn't work out of the box

请原谅我后面的代码墙,但每个块只有一个小的变化,每个变化都有注释。

我正在尝试使用 Sidewaffle 模板包附带的 Angular+Typescript "controller as" 模板。这就是开箱即用的模板。我在这里对模板所做的唯一修改是注释、空格以及将 'app1' 重命名为 'app':

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    controllerId: string; //This won't work...
    changeGreeting: () => void;
}
class testController implements ItestController {
    static controllerId: string = "testController"; //...because this is static.
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }
    changeGreeting() {
        this.greeting = "Bye";
    }
}
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', ($scope, $http, $resource) =>
        new testController($scope, $http, $resource)
    ]);

首先要注意的是,它甚至不会编译,因为控制器 class 上的静态 controllerId 成员和 controllerId 成员是 Icontroller界面。由于接口的成员需要在 class 类型的实例端实现,所以这行不通。

这很烦人,但很容易解决,尽管这样做会丢失一些类型检查:

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    changeGreeting: () => void;
}
class testController implements ItestController {
    //we leave the static member on the class and remove the member
    //from the interface
    static controllerId: string = "testController";
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }
    changeGreeting() {
        this.greeting = "Bye";
    }
}
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', ($scope, $http, $resource) =>
        new testController($scope, $http, $resource)
    ]);

现在可以编译了,但问题是对 app.controller() 的调用如何转换为 javascript。它没有将构造函数直接传递给 app.controller(),而是包装在一个匿名函数中,我们最终得到的是构造函数中的构造函数:

var testController = (function () {
    function testController($scope, $http, $resource) {
        this.$scope = $scope;
        this.$http = $http;
        this.$resource = $resource;
        this.greeting = "Hello";
    }
    testController.prototype.changeGreeting = function () {
        this.greeting = "Bye";
    };
    testController.controllerId = "testController";
    return testController;
})();
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource',
    //Why won't this work? Why would we want to do this in the first place?
    function ($scope, $http, $resource) { 
        return new testController($scope, $http, $resource); 
    }
]);

现在,当我们尝试在视图中使用 "controller as" 语法时,Angular 无法找到别名控制器 - 视图绑定到一个空对象。

据我所知,Typescript 模板应该如下所示:

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    changeGreeting: () => void;
}
class testController implements ItestController {
    static controllerId: string = "testController";
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }

    changeGreeting() {
        this.greeting = "Bye";
    }
}
//Now we're passing the controller constructor directly instead of
//wrapping the constructor call in another constructor
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource',testController]);

编译成这个 javascript:

var testController = (function () {
    function testController($scope, $http, $resource) {
        this.$scope = $scope;
        this.$http = $http;
        this.$resource = $resource;
        this.greeting = "Hello";
    }
    testController.prototype.changeGreeting = function () {
        this.greeting = "Bye";
    };
    testController.controllerId = "testController";
    return testController;
})();

app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', testController]);

效果很好。所以我有两个主要问题:

  1. 为什么您想要将控制器构造函数包装在 lambda 中以传递给 Angular 的 controller() 方法而不是直接传递构造函数?
  2. 为什么模板在 class 上有一个静态成员,它试图用 class 实现的接口上的成员强制执行?

我唯一的猜测是,这两个问题在 Typescript 和 Angular 的某些早期版本组合中都不是问题,但我不知道,因为我对这两个问题都很陌生。我正在使用 Typescript v1.4 和 Angular v1.3.14

Why would you ever want to wrap the controller constructor in a lambda to hand to Angular's controller() method instead of handing over the constructor directly?

你不会。我不 https://www.youtube.com/watch?v=WdtVn_8K17E

Why would the template have a static member on a class that its trying to enforce with a member on the interface that the class implements

关于 controllerId: string; //This won't work... 在接口上拥有一个成员并使用 class 实现该接口意味着 class 的实例将拥有该成员.然而,你想说的是 class 有这个成员。这不能通过 实现接口 来完成。

您可以通过其他方式确保这一点:

var mustHaveId:{controllerId:string};

class Fail{}
class Pass{static controllerId = "Pass"}

mustHaveId = Fail; // Error 
mustHaveId = Pass; // Pass

查看 source code on Github 发现有问题的模板是 "updated to be Typescript 1.0 and Angular 1.3 compatible," 因此,结合 Angular 和 Typescript 的先前版本,模板中的所有内容都必须具有过去曾工作过。

我的两个问题在更新的文件中得到了解决,所做的更改与我为获取东西所做的更改相似运行。 Sidewaffle 模板包尚未相应更新。

更新: 在撰写本文时,最新版本的 Sidewaffle 模板包含固定模板。