Skip to content

Module/class augmentation doesn't work #11406

Closed

Description

@MoonStorm

TypeScript Version: 2.0.3

Code

// A *self-contained* demonstration of the problem follows...
// rxjs installed via npm
// seems to expose everything via its .d.ts file:
export { Observable } from './Observable';

// attempting to augment the Observable class exposed by the rxjs module
// observable.operators.ts
import {Observable} from 'rxjs'

declare module 'rxjs' {
    interface Observable<T> {
        doStuff():void;
    }
}

// consumer.ts
import { Observable, Subscription } from 'rxjs'
export class Consumer{
  private _sub:Subscription;
   constructor(){
      this._sub = Observable.from([1,2,3]).subscribe();
   }
}

Expected behavior:
The doStuff to appear available in the rxjs module on the Observable class.

Actual behavior:
Attempting to use import {Observable} from 'rxjs' in another file (consumer.ts) causes compilation errors.

Export declaration conflicts with exported declaration of 'Observable'
Property 'subscribe' does not exist on type 'Observable'
etc.

Activity

  1. RyanCavanaugh commented on Oct 5, 2016

    @RyanCavanaugh
    Member

    I don't see any calls to doStuff in your repro code. Please don't make us guess.

  2. MoonStorm commented on Oct 5, 2016

    @MoonStorm
    Author

    More info added in the description of the problem.

    The doStuff doesn't matter. Ironically enough, a similar example using Observable was posted in the TS guidebook. In that sample, the augmentation is done at the same level as the Observable.d.ts file with import {Observable} from './Observable', as if we're gonna augment modules straight in the their folder, inside node_modules!?

  3. RyanCavanaugh commented on Oct 5, 2016

    @RyanCavanaugh
    Member

    The correct declaration looks like this:

    import {Observable} from 'rxjs'
    
    declare module 'rxjs/Observable' {
        interface Observable<T> {
            doStuff():void;
        }
    }
    import { Observable, Subscription } from 'rxjs'
    export class Consumer{
      private _sub:Subscription;
       constructor(){
          this._sub = Observable.from([1,2,3]).subscribe();
          Observable.from([1, 2]).doStuff(); // OK
       }
    }
  4. added
    QuestionAn issue which isn't directly actionable in code
    and removed
    Needs More InfoThe issue still hasn't been fully clarified
    on Oct 5, 2016
  5. MoonStorm commented on Oct 5, 2016

    @MoonStorm
    Author

    Yep, that works. Thanks.
    Could you please update the docs with this example, in the module augmentation section as well as in what's new ? Nobody is going to augment rxjs's Observable straight in the external module's own folder.

  6. RyanCavanaugh commented on Oct 5, 2016

    @RyanCavanaugh
    Member

    The example is just supposed to be an example and it doesn't mention rxjs at all. Do we need to use class names that no one has ever used before?

  7. MoonStorm commented on Oct 5, 2016

    @MoonStorm
    Author

    Haha, no of course not. Just saying you've picked a name of a very popular and extendable class of a very well known library. I bet I'm not going to be the only one being thrown off by that example.

  8. mhegazy commented on Oct 5, 2016

    @mhegazy
    Contributor

    my bad. that example was actually modeled after RXJS code a la: https://github.com/ReactiveX/rxjs/blob/master/src/add/operator/map.ts. in hind sight, probably not the best example for the general public.

  9. MoonStorm commented on Oct 5, 2016

    @MoonStorm
    Author

    No worries. It would probably be much useful to show how to augment an external module, may that be ''rxjs'' or a fictive one.

    I had never seen a module declaration like that. The augmentation seems inconsistent with the way module externals are being used regularly. Is that because the ''Observable'' is being re-exported by the lib's main module? Aren't we tying ourselves up with the inner structure of the external module?

  10. RyanCavanaugh commented on Oct 6, 2016

    @RyanCavanaugh
    Member

    Is that because the ''Observable'' is being re-exported by the lib's main module? Aren't we tying ourselves up with the inner structure of the external module?

    Correct. It's tricky because it's not apparent that augmenting an alias should effect the underlying thing (what if it was aliased under a completely different name?). But this is how the runtime generally has to operate as well for augmentation -- if you're not setting on the correct root object, it may not work.

  11. MoonStorm commented on Oct 6, 2016

    @MoonStorm
    Author

    I undestand now. Obviously not a vey sustainable solution long term. The runtime could be helped through a keyword acting as a hint that an augmentation is at play, which means the root needs to be resolved and changed?

  12. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions