Skip to content

Generating Type Definitions from Javascript is blocked by requiring private name #37832

Closed

Description

@nbbeeken

TypeScript Version: 3.9.0-dev.20200407

Search Terms:

  • TS9006
  • Declaration emit for this file requires using private name
  • Explicit type annotation
  • Unblock declaration emit.

Code

// thing.js // maybe something from deep in my library
'use strict';
class Thing {}
module.exports = { Thing };
// index.js
"use strict";
const Thing = require("./thing").Thing;
module.exports = { Thing }; // re-export to the world

tsconfig.json:

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "declaration": true,
    "emitDeclarationOnly": true,
    "declarationDir": "types",
    "strict": false,
    "target": "ES2018",
    "module": "commonJS",
    "moduleResolution": "node",
    "lib": ["ES2018"]
  },
  "include": ["index.js", "thing.js"]
}

Expected behavior:
I believe I should get two declaration files out of this that would look something like:

// thing.d.ts
export class Thing {}
// index.d.ts
import { Thing } from './thing';
export { Thing };

Actual behavior:
index.d.ts fails to be emitted with the error:

TS9006: Declaration emit for this file requires using private name 'Thing' from module '"/Users/neal/Desktop/privateNameTSC/thing"'. An explicit type annotation may unblock declaration emit.

It's not clear to me how to annotate the module.exports to make the "name" not private anymore
Thanks for taking a look.

Playground Link: Can't because imports related but I made a minimum repro here: https://github.com/nbbeeken/private-name-error-tsc

Related Issues: #9865

Activity

  1. sandersn commented on Apr 7, 2020

    @sandersn
    Member

    This is broken in 3.8 and 3.9 at least.

  2. mbroadst commented on Apr 8, 2020

    @mbroadst

    Nathan Shively-Sanders (@sandersn) thank you kindly for the quick triage. This is a bit of a roadblock for our migration to TypeScript, would it be helpful if we tried to fix this locally? Or is there already someone on your end that will begin work shortly?

  3. sandersn commented on Apr 8, 2020

    @sandersn
    Member

    From talking to Wesley Wigham (@weswigham) about a similar issue (probably the same issue), it's an unfortunate limitation in the way that we bind module.exports = { Thing }; although it looks like it could be translated to export { Thing }, we actually have to treat it as

    declare const _tmp: { Thing: Thing }
    export = _tmp

    It's probably possible to special-case this exact pattern and emit export { Thing }.
    Wesley Wigham (@weswigham) if you can weigh in, you know more about this than I do.

    Matt Broadstone (@mbroadst) I put this in 4.0 assuming that the real fix would be complex.

  4. weswigham commented on Apr 8, 2020

    @weswigham
    Member
  5. jamesopti commented on Jun 26, 2020

    @jamesopti

    Is there a workaround for this to prevent the CLI from erroring?

    I tried "checkJs": false, but to no avail

  6. Anton-Loginov commented on Jul 9, 2020

    @Anton-Loginov

    Neal Beeken (@nbbeeken) Try to "allowJs": false, I think it helps you.

  7. nbbeeken commented on Jul 9, 2020

    @nbbeeken
    Author

    Neal Beeken (@nbbeeken) Try to "allowJs": false, I think it helps you.

    I appreciate the help! unfortunately that doesn't seem to work. The goal is to generate types from jsDoc comments so tsc needs to allow .js files as input. Here's the errors you get if allowJs is false: (setting checkJs to false just removes the TS5052 error)

    error TS5052: Option 'checkJs' cannot be specified without specifying option 'allowJs'.
    
    error TS18003: No inputs were found in config file './types/tsconfig.json'. Specified 'include' paths were '["index.js","thing.js"]' and 'exclude' paths were '["types"]'.
    
  8. 12 remaining items

  9. glen-84 commented on Oct 25, 2020

    @glen-84

    Bnaya Peretz (@Bnaya),

    You can just clone the stylelint repo, update TS, and add the following to the tsconfig.json file:

            "declaration": true,
    	"emitDeclarationOnly": true,
    	"outDir": "types-new"

    (and optionally remove "noEmit": true, which is not needed)

    Then run npx tsc.

  10. Bnaya commented on Oct 25, 2020

    @Bnaya

    Glen (@glen-84) While the error is the same, it's not the same issue,
    see my workarounds there:
    https://github.com/stylelint/stylelint/pull/5004/files
    (types are now emitted)

    What we are missing there to make it nicer is a way to export type from ts-jsdocs.

    Also: seems like you are depending there on types from @types/stylelint package,
    I think it might trip typescript in the endgame when you have real stylelint package with it's own type, but that tries to import types from stylelint in expectation that it will go to @types/stylelint

  11. glen-84 commented on Oct 26, 2020

    @glen-84

    Bnaya Peretz (@Bnaya),

    What we are missing there to make it nicer is a way to export type from ts-jsdocs.

    So this is triggered by the use of @typedef to define a type, instead of importing the type each time? Should it work?

    Do you know if there is an existing GitHub issue for this?

    Also: seems like you are depending there on types from @types/stylelint package

    Where do you see that?

    (note: I am not a maintainer of stylelint)

  12. Bnaya commented on Oct 26, 2020

    @Bnaya

    So this is triggered by the use of zouying (@typedef) to define a type, instead of importing the type each time? Should it work?

    I believe something like that

    Do you know if there is an existing GitHub issue for this?

    I think not

    Where do you see that?

    Example: import('stylelint').DisabledRange

  13. glen-84 commented on Oct 26, 2020

    @glen-84

    I think not

    Okay, I'll probably open one.

    Example: import('stylelint').DisabledRange

    This resolves to the local types in the types directory, not an @types package. These types would likely be removed once they can be generated automatically via TypeScript.

  14. Bnaya commented on Oct 26, 2020

    @Bnaya

    This resolves to the local types in the types directory, not an Types (@types) package. These types would likely be removed once they can be generated automatically via TypeScript.

    I'de say to relocate them, and import them as regular source files, and not like so (It will break if you publish)
    But let's stop hijacking this issue, if there's somewhere else you are working on this, i'de love to help

  15. ggreco commented on Oct 26, 2020

    @ggreco

    Here is a minimal example, less than 20 lines in total, it gives the error of this bug both on typescript 4.0 that on 4.1 beta:

    https://github.com/ggreco/doc2dec

    • checkout the repo
    • npm install
    • npm run build
  16. glen-84 commented on Oct 26, 2020

    @glen-84

    Gabriele Greco (@ggreco) Will you create a new issue?

  17. Bnaya commented on Oct 26, 2020

    @Bnaya

    Here is a minimal example, less than 20 lines in total, it gives the error of this bug both on typescript 4.0 that on 4.1 beta:

    https://github.com/ggreco/doc2dec

    • checkout the repo
    • npm install
    • npm run build

    Ugly workaround:
    use import('./rectangle').Rectangle

  18. ggreco commented on Oct 26, 2020

    @ggreco

    Gabriele Greco (@ggreco) Will you create a new issue?

    I created a new bug for this, #41250

    Bnaya Peretz (@Bnaya) thanks for the workaround, it works, but it totally destroy the jsdoc markup for javascript users of the library...

  19. weswigham commented on Oct 28, 2020

    @weswigham
    Member

    Additionally, this bug still persist, see this repro:
    https://gist.github.com/Bnaya/f88130a9321b2706e1745f8695ff9664

    When trying to avoid the above crash, i've set the imported class to an intermediate variable, and exported it.
    that leads again to the "using private name" error

    This is fixed in latest master (likely by a combination of the other fixes going in) and now emits

    //// [lib.d.ts]
    /**
     * @param {string} a
     */
    export function bar(a: string): string;
    export class SomeClass {
        a(): number;
    }
    //// [main.d.ts]
    export const IntermediateClass: typeof SomeClass;
    import { SomeClass } from "./lib";

    If anyone comes back to this thread using latest nightly TS and thinks they have "the same bug" - please open a new thread with your repro - tracking stuff in closed issues is hard - thanks~

  20. rajsite commented on Oct 17, 2022

    @rajsite

    Edit: Posting here as I don't have a reduced reproducing example yet but wanted to share until I have one.

    Neal Beeken (@nbbeeken), I had a case somewhat similar to yours, where our app was exporting a function that set a property (which I think TypeScript recognizes as a constructor):

    module.exports = function(key) {
        const myImpl = implementations[key];
        this.invoke = myImpl.invoke;
    };

    and it was throwing this error: error TS9005: Declaration emit for this file requires using private name 'exports'. An explicit type annotation may unblock declaration emit.

    By changing module.exports to exports, the compiler error went away. I'm not sure if this actually worked, but it did get rid of the error. 🤷‍♂️

    I am seeing a similar error message in TypeScript 4.3.2 with the following pattern:

    /* data_listener.js */
    export function createDataListener() {
        return async function dataListener(someObj, x, y) {
            // `this` references the model instance
           this.blah = something;
        };
    }
    
    /* create.js */
    import {createDataListener} from "../data_listener";
    someObj.setDataListener(createDataListener().bind(model, someObj));

    I tried removing the this reference as a hint from the quoted comment (maybe TypeScript thinks the returned function is being used as a constructor function when it is not) and I'm able to compile that code:

    /* data_listener.js */
    export function createDataListener() {
        return async function dataListener(model, someObj, x, y) {
           model.blah = something;
        };
    }
    
    /* create.js */
    import {createDataListener} from "../data_listener";
    someObj.setDataListener(createDataListener().bind(undefined, model, someObj));
  21. added a commit that references this issue on Feb 12, 2024
  22. 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

BugA bug in TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions