8

私は現在、実装ではなくインターフェイスに対してプログラムするためにいくつかのコードをクリーンアップしようとしていますが、その方法がわかりません。

より具体的には、以下を使用しています: * TypeScript 1.5.0 beta -> ES5 / commonjs にトランスパイル * SystemJS を使用してモジュールをロード

現在、次のように外部モジュールを使用しようとしています。

posts.service.ts ファイル:

///<reference path="../../../typings/tsd.d.ts" />
///<reference path="../../../typings/typescriptApp.d.ts" />
...
export interface PostsService{ // 1
    fetchPosts(): Rx.Observable<any>;
}
export var PostsService:PostsServiceImpl; // 2
...
export class PostsServiceImpl implements PostsService { // 3
    ...
    constructor(){
        console.log('Loading the Posts service');
}
...
fetchPosts(): Rx.Observable<any>{ 
   ...
}

そのモジュールは posts.ts にインポートされます。

    ///<reference path="../../../typings/tsd.d.ts" />
    ///<reference path="../../../typings/typescriptApp.d.ts" />

    import {PostsService, PostsServiceImpl} from 'components/posts/posts.service';

    @Component({
    selector: 'posts',
    viewInjector: [
        //PostsServiceImpl
        //PostsService
        bind(PostsService).toClass(PostsServiceImpl)
    ]
})
...
export class Posts {
    private postsServices: PostsService;

    constructor(postsService: PostsService) {
        console.log('Loading the Posts component');
        this.postsServices = postsService;
        ...
    }

    ...
}

上記のコードは正しくコンパイルされますが、基本的に私の問題は、Angular が Posts コンポーネントに PostsServiceImpl のインスタンスを挿入しないという事実に要約されます。

もちろん、それは単に、すべてを宣言/エクスポート/インポートする正しい方法が見つからないためです

がないexport interface PostsService ...と、投稿コントローラーで使用するため、TS コンパイル エラーが発生します。

@Viewexport var PostsService:PostsServiceImpl;デコレータの viewInjector で TS コンパイル エラーが発生します。

生成されたjsコードexports.PostsService;では、エクスポート変数のために追加されたものしか見つかりません...インターフェイスが実行時に消えることはわかっています。

だから私はこのすべてに少し迷っています。TypeScript & Angular 2 でインターフェースベースのプログラミングをどのように使用できるかという実用的なアイデアはありますか?

4

4 に答える 4

6

TypeScript と Angular 2 を使用してインターフェイス ベースのプログラミングをどのように使用できるかについての実用的なアイデア

インターフェイスは実行時に消去されます。実際、デコレーターもインターフェースをサポートしていません。したがって、実行時に存在するもの (つまり、実装) を使用する方がよいでしょう。

于 2015-07-03T08:34:59.037 に答える
4

クラスは抽象化に依存する可能性がある(そしてそうすべきである)ことに注意する必要がありますが、抽象化を使用できない場所が 1 つあります。それは Angular の依存性注入です。

Angular は、使用する実装を認識している必要があります。

例 :

/// <reference path="../../../../../_reference.ts" />

module MyModule.Services {
    "use strict";

    export class LocalStorageService implements ILocalStorageService {
        public set = ( key: string, value: any ) => {
            this.$window.localStorage[key] = value;
        };

        public get = ( key: string, defaultValue: any ) => {
            return this.$window.localStorage[key] || defaultValue;
        };

        public setObject = ( key: string, value: any ) => {
            this.$window.localStorage[key] = JSON.stringify( value );
        };

        public getObject = ( key: string ) => {
            if ( this.$window.localStorage[key] ) {
                return JSON.parse( this.$window.localStorage[key] );
            } else {
                return undefined;
            }
        };

        constructor(
            private $window: ng.IWindowService // here you depend to an abstraction ...
            ) { }
    }
    app.service( "localStorageService",
        ["$window", // ... but here you have to specify the implementation
            Services.LocalStorageService] );
}

したがって、テストでは、すべてのコントローラー/サービスなどが抽象化に依存しているため、モックを簡単に使用できます。しかし、実際のアプリケーションでは、Angular の実装が必要です。

于 2015-07-03T09:11:17.057 に答える
3

TypeScript はインターフェイスのシンボルを生成しませんが、依存性注入を機能させるには何らかのシンボルが必要になります。

解決策: OpaqueTokens をシンボルとして使用し、provide() 関数を介してそのトークンにクラスを割り当て、クラスのコンストラクターでそのトークンを使用して Inject 関数を使用します。

ここの例では、Posts コンポーネントの PostsService に PostsServiceImpl を割り当てたいと想定しています。コードがすべて同じ場所にあると説明が簡単だからです。provide() 呼び出しの結果は、angular.bootstrap(someComponent, arrayOfProviders) の 2 番目の引数、または Posts コンポーネントより上位の階層にあるコンポーネントの provide[] 配列に入れることもできます。

components/posts/posts.service.ts:

import {OpaqueToken} from "@angular/core";
export let PostsServiceToken = new OpaqueToken("PostsService");

コンストラクターで:

import {PostsService, PostsServiceImpl, PostsServiceToken} from 'components/posts/posts.service';
import {provide} from "@angular/core";
@Component({
    selector: 'posts',
    providers: [provide(PostsServiceToken, {useClass: PostsServiceImpl})]
})
export class Posts {
    private postsServices: PostsService;

    constructor(
        @Inject(PostsServiceToken)
        postsService: PostsService
        ) {
        console.log('Loading the Posts component');
        this.postsServices = postsService;
        ...
    }

    ...
}    
于 2016-08-11T03:22:30.583 に答える