-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interface merge of import/local should error when the import is re-exported with export *
#9532
Comments
cc @blakeembrey to see if it rings any bell on similar issues. |
Expanding this to cover one more issue: // foo.ts
declare module 'A' {
export interface Foo<S> {
(): void;
}
export class SomeClass<S> {
foo: Foo<S>;
}
}
declare module '~B' {
import { Foo as Roo, SomeClass } from 'A';
export { SomeClass }
interface Foo extends Roo<any> {
}
}
declare module 'B' {
export * from '~B';
}
// boo.ts
import { Foo as Soo } from 'A';
declare module 'B' {
interface Foo extends Soo<any> { // <-- i.e. matching original extends
(message: string): any;
}
}
export const SOME = 1;
// go.ts
import { Foo, SomeClass } from 'B';
let x: Foo;
x(); // <-- has overloads
let y: SomeClass<any>;
y.foo(); // <-- no overloads |
This issue is more common than I thought. It would happen if I wrote a module distributed through npm this way: // index.ts
export * form './a';
export * from './b';
// a.ts
...
// b.ts
... Which is a pretty common pattern. |
Maybe related: #9127 |
This is basically a duplicate of #8140. You can't augment things that are imported from a module, even types. But the bad error you found is different than #8140. I'll give more detail in a subsequent comment. I'll include a modified repro and an explanation of why this fails to do what you want. |
export *
Not sure if I understand. |
Here's the explanation I promised. I assume that you are trying to augment the declare module 'B' {
export * from '~B'; // import and re-export `Foo`
} TypeScript should error here. And it does -- if you explicitly say In boo.ts, you could |
I forgot to mention earlier that TypeScript skips the re-exported Here's the modified repro that uses properties: // foo.ts
declare module 'A' {
export interface Foo {
foo: number; // diff 1: use property instead of call signature
}
}
declare module '~B' {
import { Foo as Roo } from 'A';
interface Foo extends Roo {
baz: boolean; // diff 2: add property
}
}
declare module 'B' {
export * from '~B';
}
// boo.ts
declare module 'B' {
interface Foo {
bar: string; // diff 3: use property instead of call sig
}
}
export const SOME = 1;
// go.ts
import { Foo } from 'B';
let x: Foo = { // diff 4: initialise to object literal
foo: 1, // error: 'foo' does not exist in type 'Foo'
bar: 'maybe',
baz: false, // error: 'baz' does not exist in type 'Foo'
}; The simplest fix is a one-liner. In boo.ts, augment // boo.ts
declare module '~B' {
interface Foo {
bar: string;
}
} I tried your fix to this modified repro but it still says that 'baz' does not exist in type 'Foo': // boo.ts
import { Foo as Soo } from 'A';
declare module 'B' {
interface Foo extends Soo {
bar: string;
}
}
export const SOME = 1; The reason that this doesn't work is that the re-export is still skipped so |
Does that means module written like this: // index.ts
export * form './a';
export * from './b';
// a.ts
...
// b.ts
... cannot be augmented? |
Also, this could cause issue on |
When you say "Interface merge of alias/local should error when the alias is re-exported with |
Which module do you want to augment? |
No, it is the I think this could indeed be an issue for |
The term "alias" is misleading. Internally, the compiler refers to any imported symbol as an alias, whether it actually uses the |
export *
export *
Do you mean |
a What tool fails to produce the error? I see it in VS Code and running |
That's strange. I am using VSCode. It doesn't work for both past and today's release. With 7/5 TS nightly. |
Is this a technical limitation or there are use case for this limitation? |
Thanks @unional, sounds like it. I had assumed this was fixed, but I guess I reviewed it incorrectly. For reference, there's a whole chain of issues starting from typings/typings#525 (comment). Also, being unable to augment any |
I looked it up and it fixed the export default and augmentation in ADDING interface: #8840 But this is about augmenting existing interface (i.e. merging). |
Also on the js front it is common: https://github.com/lodash/lodash/blob/es/lodash.js |
It's a technical limitation. I don't know yet if it's by design (and if so, if there's an intended workaround) -- I'm waiting on @RyanCavanaugh to get back from vacation since he knows much more than I do about typings. |
Unfortunately, after some more discussion with the team, we decided that we can't support this pattern for now. We might revisit this decision in the future, but current DefinitelyTyped code has worked around this limitation so far, which may indicate that it's (1) easy to work around or (2) not that common. |
@sandersn Unless I've misunderstood something, isn't this extremely common? Basically any node module that's re-exporting from multiple files follows this pattern (which is most node modules, you can regularly find anything bigger than a single function util exporting multiple files in DefinitelyTyped "works around it" because it mutates the global scope. The only other possible work-around in ordinary code would be to augment the original source file. But that means any file in a module is now part of the public API, which is frowned upon doing and quite fragile. |
@RyanCavanaugh Thoughts? You've worked with DefinitelyTyped a lot more than I have. |
@RyanCavanaugh what's your thought? I have a private library written in TypeScript that hit this limitation. This bug prevents that from happening. My workaround is put all source code into IMO this bug needs to be re-opened. |
Pinging @RyanCavanaugh |
Any update on this? We should reconsider this, not just for typings, for package written in TypeScript in general. |
TypeScript Version: (2.0.0-dev.20160705)
Code
Expected behavior:
x();
have overloads of(message: string): any
and(): void
Actual behavior:
x();
only have(message: string): any
If I change
boo.ts
to:Then it works correctly.
Also, if I reference
~B
instead ofB
(i.e. without re-export), it works correctly too:The text was updated successfully, but these errors were encountered: