Skip to content

Incorrect declaration emit for allowJs JavaScript class with static members imported from other files #33777

Closed

Description

TypeScript Version: 3.7.0-dev.20191002

Search Terms:

Code

Emitted index.d.ts from these JS files using --declaration --allowJs has an avoidable semantic error. It looks like the compiler usually avoids this error, but in this particular case it doesn't.

// foo.js
function foo() {}
export {foo}
// index.js
import {foo} from './foo'

export {MyClass}
function MyClass() {}
MyClass.prototype = {
  method() {}
}
MyClass.foo = foo

Expected behavior:

This declaration is emitted:

// index.d.ts
export function MyClass(): void;
export class MyClass {
    method(): void;
}
export namespace MyClass {
    export { foo };
    import { foo } from "./foo";
}
export {};

Actual behavior:

This declaration is emitted:

// index.d.ts
export function MyClass(): void;
export class MyClass {
    method(): void;
}
export namespace MyClass {
    export { foo };
}
declare var foo: typeof foo;     // <-- foo circularly references self
import { foo } from "./foo";     // <-- import foo conflicts with var foo
export {};
//# sourceMappingURL=index.d.ts.map

It appears to be triggered by the combination of both function MyClass and MyClass.prototype = assignment. Removing one or the other fixes the bug, so that the import {foo} from './foo'; is nested within export namespace MyClass as in the "expected behavior" above.

Playground Link:

Related Issues:

Activity

  1. weswigham commented on Oct 30, 2019

    @weswigham
    Member

    To the OP: This should now be fixed on master (so should go out in the next nightly) and in the next 3.7 cut (which should be final release at this point?), by #34786 (essentially a dupe of one of the reports in #33626)

    Your expected emit is a lil off though; we emit:

    //// [foo.d.ts]
    export function foo(): void;
    //// [index.d.ts]
    export function MyClass(): void;
    export class MyClass {
        method(): void;
    }
    export namespace MyClass {
        export { foo };
    }
    import { foo } from "./foo";

    you're not allowed to have an import statement in a namespace, and the top-level export {}; is unneeded in your example (as something in the file is exported, so the file's definitely a module, and there's no privates which need their scoping preserved)~

  2. added
    DuplicateAn existing issue was already created
    FixedA PR has been merged for this issue
    and removed
    BugA bug in TypeScript
    on Oct 30, 2019
  3. typescript-bot commented on Nov 2, 2019

    @typescript-bot
    Contributor

    This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  4. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

DuplicateAn existing issue was already createdFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions