Allow augmentation of re-exported module
christianacca opened this issue · 15 comments
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:
- As library author I am free to reorganise the modules into sub-folders as the library code base grows without breaking consumers
- 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
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 @RyanCavanaugh comment
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.
Hi @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
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'.
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.
I've hit the same problem. It is important to have a solution to this problem.
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!
Ah, this is why it's not working. I'm trying to do the same thing as @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 */}
}I keep running into this issue over again, forgetting that I can't augment re-exported modules. Would be great if this were fixed.
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.
duplicate of #8545?
It is important to fix this issue because, as @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
{
}
}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.
Is this still happening?
I think as long as the declared module path and the import path are the same, it works now.
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