Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

I'm currently trying to clean up some code in order to program against interfaces rather than against implementations but can't figure out how to.

To be more specific, I'm using: * TypeScript 1.5.0 beta -> transpiled to ES5 / commonjs * SystemJS to load the modules

I currently try to use external modules as follows:

posts.service.ts file:

///<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>{ 
   ...
}

and that module is imported in 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;
    ...
}

...

}

The above code compiles correctly, but basically my issue boils down to the fact that Angular won't inject an instance of PostsServiceImpl in the Posts component.

Of course it's simply because I don't find the correct way to declare/export/import everything

Without export interface PostsService ..., I get TS compilation errors because I use it in the posts controller.

Without export var PostsService:PostsServiceImpl; I get TS compilation errors in the @View decorator's viewInjector

In the generated js code I only find exports.PostsService; which is added because of the export var... I know that interfaces disappear at runtime.

So I'm a bit lost in all this. Any practical ideas how I can use interface based programming w/ TypeScript & Angular 2?

share|improve this question
up vote 2 down vote accepted

Any practical ideas how I can use interface based programming w/ TypeScript & Angular 2

Interfaces are erased at runtime. In fact decorators don't support interfaces either. So you are better off using something that does exist at runtime (i.e. implementations).

share|improve this answer
    
This is sad news for me ;-). I guess I should just adapt and forget my fully typed Java world.. ^^ – dSebastien Jul 3 at 8:57
    
How should I then approach decoupling in my application? I'm not there yet, but my goal is to write testable code. Afaik there's no support yet for Abstract classes in TypeScript, right? – dSebastien Jul 3 at 8:59
1  

You have to keep in mind that your class may (and should) depend on abstractions, but there is one place where you can't use abstraction : it's in the dependency injection of Angular.

Angular must know what implementation to use.

Example :

/// <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] );
}

So in your test you can use mocks easily as all your controllers/services etc depend on abstractions. But for the real application, angular needs implementations.

share|improve this answer
    
Well my (naive) idea was to use bind(PostsService).toClass(PostsServiceImpl) exactly for this, letting Angular know how to map from abstract to concrete. That could've made sense if interfaces weren't erased at runtime as pointed out by @basarat. As far as the client code was concerned, I would've like to fully hide the fact that a specific implementation was being injected. – dSebastien Jul 3 at 12:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.