私はAngularJSとTypeScriptを使用しています。次のように、TypeScriptクラスを使用してAngularJSサービスを実装します。
class HelloService {
public getWelcomeMessage():String {
return "Hello";
}
}
angular.module('app.services.helloService', []).factory('helloService', () => {
return new HelloService();
});
これは、次のjavascriptコードにコンパイルされます。
var HelloService = (function () {
function HelloService() {
}
HelloService.prototype.getWelcomeMessage = function () {
return "Hello";
};
return HelloService;
})();
angular.module('app.services.helloService', []).factory('helloService', function () {
return new HelloService();
});
これは、グローバルな名前空間を変数HelloServiceで汚染しますが、これは明らかに望ましくありません。 (Chromeのコンソールを使用して、HelloServiceがオブジェクトであることを確認しました。)この問題を解決/回避するにはどうすればよいですか?
私は明白なことを試しました:
angular.module('app.services.helloService', []).factory('helloService', function () {
class HelloService { ...}
return new HelloService();
});
しかし、それは私にコンパイルエラーを与えます(「予期しないトークン。「ステートメント」が必要です。))。
私が考えることができる1つの可能な解決策は、TypeScriptのインポートとエクスポートを何らかの方法で使用することです。これは、RequireJSを使用します。これはおそらく、定義関数内でHelloServiceをラップし、HelloServiceによるグローバルスコープの汚染を回避します。ただし、AngularJSは私の使用には十分であり、複雑さを増すため、AngularJSアプリケーションでRequireJSを使用したくありません。
だから、私の質問は、グローバルスコープを汚染しないTypeScriptクラスを使用してAngularJSサービスをどのように定義できますか?
私が実際にやったことを提供する必要があります:
module MyModule {
export class HelloService {
public getWelcomeMessage():String {
return "Hello";
}
}
angular.module('app.services.helloService', []).factory('helloService', () => {
return new HelloService();
});
}
このように私は使用できます
return new HelloService();
の代わりに
return new MyModule.HelloService();
静的な$inject
配列とコンストラクターは、前の例から変更されていません。
唯一の変更は、クラスを複数のファイルに分割し、ES6モジュールを使用してクラス定義をプルすることです。
/ lib/HelloService.ts:
export class HelloService {
public getWelcomeMessage():String {
return "Hello from HelloService";
}
}
/ lib/AnotherService.ts:
import {HelloService} from './HelloService';
/**
* Service that depends on HelloService.
*/
export class AnotherService {
// Define `HelloService` as a dependency.
static $inject = ['HelloService'];
constructor(
// Add the parameter and type definition.
public HelloService: HelloService
){}
public getWelcomeMessage():String {
// Access the service as: `this.HelloService`
// Enjoy auto-completion and type safety :)
var helloMsg = this.HelloService.getWelcomeMessage();
return "Welcome from AnotherService, " + helloMsg;
}
}
/ index.ts:
// Using the services.
import {HelloService} from './lib/HelloService';
import {AnotherService} from './lib/AnotherService';
angular.module('HelloApp', [])
.service('HelloService', HelloService)
.service('AnotherService', AnotherService)
.run(['AnotherService', function(AnotherService: AnotherService){
console.log(AnotherService.getWelcomeMessage());
}]);
依存性注入を許可するには、クラスに静的$inject
配列を追加します。
$inject
配列がどのように機能するかについては、 Angular $ injector documentation を参照してください。
依存関係は、配列によって指定された順序でコンストラクターに注入されます(そして、縮小化で動作するようになります)。
依存性注入の例:
namespace MyModule {
/**
* Angular Service
*/
export class HelloService {
public getWelcomeMessage():String {
return "Hello from HelloService";
}
}
/**
* Service that depends on HelloService.
*/
export class AnotherService {
// Define `HelloService` as a dependency.
static $inject = ['HelloService'];
constructor(
// Add the parameter and type definition.
public HelloService: MyModule.HelloService
){}
public getWelcomeMessage():String {
// Access the service as: `this.HelloService`
// Enjoy auto-completion and type safety :)
var helloMsg = this.HelloService.getWelcomeMessage();
return "Welcome from AnotherService, " + helloMsg;
}
}
}
// Using the services.
angular.module('app.services.helloService', [])
.service('HelloService', MyModule.HelloService)
.service('AnotherService', MyModule.AnotherService)
.run(['AnotherService', function(AnotherService: MyModule.AnotherService){
console.log(AnotherService.getWelcomeMessage());
}]);
私には2つの解決策があります。1つ目はクラスベースの構文を提供し、2つ目はグローバルスコープにまったく何も残しません...
グローバルスコープに1つのハンドルを追加するだけで、わずかに妥協することができます(これは、現在1つのクラスしかないため、グローバルスコープに配置したくない複数のクラスがある場合に当てはまります)。
次のコードは、グローバルスコープ内のモジュールのみを残します。
module MyModule {
export class HelloService {
public getWelcomeMessage():String {
return "Hello";
}
}
export class AnotherService {
public getWelcomeMessage():String {
return "Hello";
}
}
}
angular.module('app.services.helloService', []).factory('helloService', () => {
return new MyModule.HelloService();
});
angular.module('app.services.anotherService', []).factory('anotherService', () => {
return new MyModule.AnotherService();
});
または、グローバルスコープに単一のものを残さないようにするには、クラスの構文を避けて「プレーンな古いJavaScript」を使用できます。
angular.module('app.services.helloService', []).factory('helloService', () => {
var HelloService = (function () {
function HelloService() {
}
HelloService.prototype.getWelcomeMessage = function () {
return "Hello";
};
return HelloService;
})();
return new HelloService();
});