Skip to content

Allow augmentation of re-exported module #12607

Open

Description

I've sadly discovered that it not possible to augment a ES2015 module that is being re-exported. At least not without specifying the full path to the ES2015 that is then being re-exported.

This has significant implications, particularly for library authors and consumers.

An example would probably help clarify.

Suppose as an authored of a library I want to expose a simple surface area from which consumers should import from. I do this by creating an index.ts file that re-exports modules from nested sub-folders like so:

// index.ts
export { AClass } from './path/to/class-a';
export { BClass } from './path/to/class-b';
export { CClass } from './path/to/class-c';

Now a consumer can import like so:

import { AClass, BClass } from 'some-library'; 

The benefits of the above:

  1. As library author I am free to reorganise the modules into sub-folders as the library code base grows without breaking consumers
  2. As library consumer I don't need to have intimate knowledge of how the library organises it's file on disk - instead I have one path to import modules and this is the name of the npm package itself.

Once augmentation enters the picture all of the above benefits are now gone.

This is really bad for everyone.

What can be done about the situation?

Thanks
Christian

Activity

  1. christianacca commented on Dec 1, 2016

    @christianacca
    Author

    Also, not being able to augment a re-exported module can cause confusion (eg: #11406) but does not necessarily have an obvious solution as per Ryan Cavanaugh (@RyanCavanaugh) comment

  2. mhegazy commented on Dec 1, 2016

    @mhegazy
    Contributor

    so, is this your library? or a library you are using?

    one thing to note, ES2015 does not allow augmenting on the top level of a module anyways. so moving forward the only augmentation allowed at runtime is augmenting export shapes themselves.

  3. christianacca commented on Dec 1, 2016

    @christianacca
    Author

    Hi Mohamed Hegazy (@mhegazy) thanks for the quick reply.

    Let's suppose this is a library I'm using that's been authored by someone else.

    In reality, I hit this issue whilst writing a demo app of a library that I'm authoring. I spent 2 hours banging my head thinking I was going crazy!

    In my case I was trying to augment an interface re-exported from ng-table

  4. blakeembrey commented on Dec 1, 2016

    @blakeembrey
    Contributor

    There was a similar discussion at #9532 (comment). The only workaround I'm aware of is to augment the specific module instead of the exported one but that has all the caveats you mentioned. E.g. declare module './path/to/class-a'.

  5. christianacca commented on Dec 1, 2016

    @christianacca
    Author

    Yup that is the workaround, but not a particularly satisfying one.

    It means the author loses the freedom to rearrange modules inside a package. The consumer also has to know the "internal" paths.

  6. doliver3 commented on Feb 19, 2017

    @doliver3

    I've hit the same problem. It is important to have a solution to this problem.

  7. endel commented on Feb 25, 2018

    @endel

    I've just hit this problem too. I'd like to augment THREE module but it's not possible.

    Tried many ways, without success, such as:

    declare namespace THREE {
        export interface Object3D {/* augmentations */}
    }
    declare module 'three' {
        export interface Object3D {/* augmentations */}
    }
    declare module 'three/three-core' {
        export interface Object3D {/* augmentations */}
    }

    Any workaround for this would be appreciated!

  8. the-reality-engineer commented on Oct 9, 2018

    @the-reality-engineer

    Ah, this is why it's not working. I'm trying to do the same thing as Endel Dreyer (@endel) (augmenting a re-exported class from the package-scoped three module).

    EDIT, this worked for me:

    declare module 'three/three-core' {
        interface Object3D {/* augmentations */}
    }
  9. the-reality-engineer commented on Feb 14, 2019

    @the-reality-engineer

    I keep running into this issue over again, forgetting that I can't augment re-exported modules. Would be great if this were fixed.

  10. RyanCavanaugh commented on Apr 1, 2019

    @RyanCavanaugh
    Member

    The OP is slightly ambiguous so I'll address both.

    If the request is to allow the exporting library to create a new type that augments AClass, that's a strong "no" due to our current architecture and potential user confusion.

    If the request is that augmentors can augment the exported AClass type as if it were declared upfront in the exporting library, 100% yes, that "should" work (where "should" is defined as "it is effectively feature work to support each possible variant, but we are on board with someone contributing that work"). Effectively, augmenting any type or value through its aliases should be the same as augmenting the type or value at its original declaration site.

  11. zpdDG4gta8XKpMCd commented on Apr 2, 2019

    @zpdDG4gta8XKpMCd

    duplicate of #8545?

  12. mmichlin66 commented on Jun 15, 2019

    @mmichlin66

    It is important to fix this issue because, as Christian Crowhurst (@christianacca) said, "the [library] author loses the freedom to rearrange modules inside a package". Notice also the inconsistency: for a consumer of a package, to use a re-exported type you just specify the package name and the type name:

    import {Type} from "library"

    To augment, however, you have to know where this type definition resides within the source tree of the library:

    declare module "library/src/dir1/dir2/file"
    {
        interface Type
        {
        }
    }
  13. J-Rojas commented on Aug 31, 2021

    @J-Rojas

    Very maddening bug... it should be documented at least somewhere the current limitation. I've wasted hours on this bug, finally found this issue to explain some of this.

    Three.js is organized is such a way that augmentation will fail as others mentioned.

  14. avin-kavish commented on Jun 23, 2022

    @avin-kavish

    Is this still happening?

    I think as long as the declared module path and the import path are the same, it works now.

  15. macarie commented on Jul 28, 2022

    @macarie

    No, I don't think this is working.

    e.g. in https://github.com/pmndrs/valtio, the useSnapshot function is exported in the index file from './react', and

    declare module 'valtio' {
      export function useSnapshot<T extends object>(p: T): T
    }

    does not augment the module, but overwrites it.

    Is the above code correct? If it is, are there any known workarounds?

    ref: pmndrs/valtio#458

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

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions