Несколько дней назад я нашел язык TypeScript. Судя по видеообзорам, для меня это выглядит довольно многообещающим, так как привносит в JavaScript соответствующее автозавершение кода, неявную документацию по коду и, возможно, делает его более безопасным по типам.

Я пытаюсь переписать простое приложение AngularJS на TypeScript. Я хотел бы указать типы параметров, которые вводятся в контроллеры. Предположим следующий JS-код:

// service.js
angular.module('app').service('MyService', MyService);
function MyService() {
    this.test = function test() { console.log('test'); };
}

// controller.js
angular.module('app').controller('MyController', MyController);
function MyController($scope, MyService) {
    $scope.test = function test() { MyService.test(); };
}

Я пытаюсь добиться чего-то вроде этого:

// controller.ts
angular.module('app').controller('MyController', MyController);
function MyController($scope, MyService:MyService) {
    // ...
}

Так было бы проще написать код контроллера с автозавершением кода для параметра MyService. Однако этот код заставляет компилятор выдавать error TS2304: Cannot find name 'MyService'.

Я пробовал пару вещей и нашел как минимум 2 возможных решения. Однако ни один из них не кажется идеальным.

1) Создание дополнительного интерфейса, декларирующего все методы сервиса. Но этот подход требует большого количества дополнительной типизации (на самом деле, мы дважды определяем один и тот же набор методов с полной подписью, а также должны обновить несколько вещей в случае изменений). Этот способ совершенно нормален, когда интерфейс реализован несколько раз, но выглядит избыточным для одной службы AngularJS.

2) Конструктор можно заменить классом. Таким образом, можно использовать имя класса как тип параметра. Однако это также приводит к нескольким проблемам:

  • Компилятор typescript преобразует определения классов в замыкания, которые присваиваются переменным, объявленным с помощью ключевого слова var (по крайней мере, для ES5). Это требует, чтобы объявление службы AngularJS было размещено после определения класса в самом низу файла. Это увеличивает возможность забыть это сделать.

    angular.module('app').service('MyService', MyService);
    class MyService {
        test() { console.log('test'); }
    }
    
    // becomes
    
    angular.module('app').service('MyService', MyService);
    var MyService = (function () {
        function MyService() {
        }
        MyService.prototype.test = function () { console.log('test'); };
        return MyService;
    }());
    
  • Таким образом, мы должны внедрить зависимости в функцию-конструктор службы. В результате необходимо каждый раз указывать лишнюю строку this. при использовании зависимости.

Итак, есть ли другие способы передать функцию-конструктор как тип параметра другой функции? Спасибо.

P.S .: Не знаю, нужно это или нет, но я использую Sublime Text 3 с официальным плагином TypeScipt и gulp-typescript для компиляции.

0
DWand 27 Фев 2016 в 16:38

1 ответ

Лучший ответ

Да, ты можешь это сделать. См. рабочий CodePen

class MyController
{
  static $inject = ['MyService','$scope'];

  constructor(private myService:MyService, private $scope:any){
    this.$scope.test = this.myService.test;
  }  
}

class MyService{  
  test(){ 
    console.log('test');
  }
}
1
rwisch45 27 Фев 2016 в 17:23
Спасибо, @ rwisch45. Вы доказали мое предположение, что единственный «нормальный» способ добиться этого - использовать классы. Вы знаете, как бороться с недостатками этого подхода, о которых я упоминал в вопросе?
 – 
DWand
1 Мар 2016 в 09:37