Typescript: Generating Type Definitions from Javascript is blocked by requiring private name

Created on 8 Apr 2020  ·  27Comments  ·  Source: microsoft/TypeScript

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



md5-aed84650a0ffeed81a01366d3982e01d




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



md5-a1a08cfd219551fd7f79ddd019ce655a



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



md5-0ca3e1f58cfc8d51229bc05d8c4d1dcc



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

Bug

Most helpful comment

@ggreco Will you create a new issue?

I created a new bug for this, https://github.com/microsoft/TypeScript/issues/41250

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

All 27 comments

This is broken in 3.8 and 3.9 at least.

@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?

From talking to @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 }.
@weswigham if you can weigh in, you know more about this than I do.

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

@sandersn you have it exactly.

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

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

@nbbeeken Try to "allowJs": false, I think it helps you.

@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"]'.

I am having the same error message without using explicit exports (tested with TypeScript 3.9.7).
We have different implementations of classes with same name in different folders (for different customers). Although this results in a naming conflict, we would be able to @ts-ignore the duplicate declarations.

Sadly, some files produce an error that cannot be ignored: Error:(1, 1) TS9005: Declaration emit for this file requires using private name 'Bla'. An explicit type annotation may unblock declaration emit.

Minimal example:

// test1/Bla.js
class Bla extends BlaBase
{

}
// test2/Bla.js
class Bla extends BlaBase
{

}



md5-db084d2d120554997740080213f7f20b



// test3/BlaBase.js
class BlaBase
{
    constructor(name)
    {
        this.name = name;
    }
}

The error message is somewhat brittle. In this toy example it goes away when adding constructors to the two Bla implementations.
However, in our real code I am unsure what is causing the issue (e.g. a specific method or field).
Could you explain what is causing the message here? Any ideas to work around the issue?

@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. 🤷‍♂️

Thanks for the suggestion @jrnail23!
I gave that a go but now there are type errors about exports not existing:

index.js:3:23 - error TS2306: File '.../test-ts-bug/thing.js' is not a module.
3 const Thing = require("./thing").Thing;
                        ~~~~~~~~~
thing.js:4:1 - error TS2304: Cannot find name 'exports'.
4 exports = { Thing };
  ~~~~~~~
Found 2 errors.

Here's a quick screenshot to show I'm using the example in the issue description.


Screenshot:



Came to this issue because I was getting the same error, even when I had declaration: false. I just tested the repro (https://github.com/nbbeeken/private-name-error-tsc) with typescript@beta (4.1.0-beta) and it no longer produces this error.

Yep, this is fixed in 4.1 -- although I found a related bug when requireing a relative path like "./thing" instead of "fs".

Are you sure this is fixed in 4.1?

npm install typescript@beta

I have the same problem both on 4.0.3 and 4.1, not sure is the exact same problem, minimal example included here:

https://stackoverflow.com/questions/64460213/create-typescript-declaration-files-for-existing-jsdoc-annotated-commonjs-librar

... maybe I did something wrong? Should I open a new ticket with the code I posted in stackoverflow?

re-exporting classes now leads to tsc crash "Unhandled alias declaration kind in symbol serializer!"
I've filed a bug report:
https://github.com/microsoft/TypeScript/issues/41182

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

@sandersn @weswigham – Can this issue be reopened?

I get the following when trying to generate definitions for stylelint (using TS 4.1.0-dev.20201025):

lib/assignDisabledRanges.js:1:1 - error TS9006: Declaration emit for this file requires using private name 'CommentExt' from module '"postcss/lib/comment"'. An explicit type annotation may unblock declaration emit.

1 'use strict';
  ~~~~~~~~~~~~

lib/descriptionlessDisables.js:1:1 - error TS9006: Declaration emit for this file requires using private name 'CommentExt' from module '"postcss/lib/comment"'. An explicit type annotation may unblock declaration emit.

1 'use strict';
  ~~~~~~~~~~~~

lib/needlessDisables.js:1:1 - error TS9006: Declaration emit for this file requires using private name 'CommentExt' from module '"postcss/lib/comment"'. An explicit type annotation may unblock declaration emit.

1 'use strict';
  ~~~~~~~~~~~~

lib/utils/parseCalcExpression/parser.js:383:13 - error TS9005: Declaration emit for this file requires using private name 'Parser'. An explicit type annotation may unblock declaration emit.

383             var parser = (function () {
                ~~~

@glen-84 can you please share a minimal repro?

@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.

@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

@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)

So this is triggered by the use of @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

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.

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.

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

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

@ggreco Will you create a new issue?

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

@ggreco Will you create a new issue?

I created a new bug for this, https://github.com/microsoft/TypeScript/issues/41250

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

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~

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartynasZilinskas picture MartynasZilinskas  ·  3Comments

Roam-Cooper picture Roam-Cooper  ·  3Comments

seanzer picture seanzer  ·  3Comments

siddjain picture siddjain  ·  3Comments

jbondc picture jbondc  ·  3Comments