Skip to content
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

Exported variable <variable name> has or is using private name <private name> #6307

Closed
jeffschwartz opened this issue Dec 31, 2015 · 13 comments
Labels
Canonical This issue contains a lengthy and complete description of a particular problem, solution, or design Docs The issue relates to how you learn TypeScript Question An issue which isn't directly actionable in code

Comments

@jeffschwartz
Copy link

The following code:

class Test {
    constructor(public someting: any){}
}

export let t = new Test("some thing");

produces the following error:

Exported variable 't' has or is using private name 'Test'.

@DanielRosenwasser
Copy link
Member

It's because you're exporting t which uses Test which hasn't been exported. You can fix this by exporting the class Test.

export class Test {
    constructor(public something: any){}
}

export let t = new Test("some thing");

@DanielRosenwasser DanielRosenwasser added the Question An issue which isn't directly actionable in code label Jan 1, 2016
@jeffschwartz
Copy link
Author

@DanielRosenwasser thanks for your quick reply. While I understand your response I feel this is still an error because:

  1. the module is only exporting an instance of the class
  2. the class doesn't define any static methods that would require its class to be called upon
  3. In situations where singletons are required forcing the exposure of a constructor to the outside world could introduce opportunities where none are intended

If there are currently constructs in the language already that address the use case that I've outlined above to a class then I apologize for my ignorance and hope you will point me in the right direction. Otherwise, wouldn't it be advisable to eliminate this error which seems to be guessing at the intention of a potential user and instead allow undefined/unresolved class errors to be flagged when users actually attempt to reference the class?

Again, thank you for your response and have a very healthy and happy New Year.

@RyanCavanaugh RyanCavanaugh added Canonical This issue contains a lengthy and complete description of a particular problem, solution, or design Docs The issue relates to how you learn TypeScript labels Jan 1, 2016
@RyanCavanaugh
Copy link
Member

This error occurs when you use the --declaration flag because the compiler is trying to produce a declaration file that exactly matches the module you defined.

Let's say you have this code:

/// MyFile.ts
class Test {
    // ... other members ....
    constructor(public parent: Test){}
}

export let t = new Test("some thing");

To produce a declaration file, the compiler has to write out a type for t:

/// MyFile.d.ts, auto-generated
export let t: ___fill in the blank___;

The member t has the type Test. The type Test is not visible because it's not exported, so we can't write t: Test.

In the very simplest cases, we could rewrite Test's shape as an object type literal. But for the vast majority of cases, this doesn't work. As written, Test's shape is self-referential and can't be written as an anonymous type. This also doesn't work if Test has any private or protected members. So rather than let you get 65% of the way through writing a realistic class and then start erroring then, we just issue the error (you're almost certainly going to hit later anyway) right away and save you the trouble.

In general you shouldn't be using classes to implement a singleton pattern in TypeScript. See http://stackoverflow.com/questions/30174078/how-to-define-singleton-in-typescript

@jeffschwartz
Copy link
Author

@RyanCavanaugh you are correct, I am generating d.ts files for my project.

@ndarilek
Copy link

Not sure if I should be asking this here, but this issue came up when I googled this error, I didn't quite feel like there was a solution, and to complicate matters further I've found other issues suggesting it once worked but now doesn't. So I'm trying to delve further into it and see if this issue might eventually describe the error case I'm hitting too.

src/index.ts(34,38): error TS4020: Extends clause of exported class 'Session' has or is using private name 'EventEmitter'.

So I'm importing EventEmitter:

import * as EventEmitter from "eventemitter3"

Then:

export default class Session extends EventEmitter {

And then, of course, hitting the above error. This issue led me to believe I should be exporting EventEmitter, but every export method I tried resulted in no change.

Further, I've found this issue which seems to imply that this is something entirely different. Here is a sample repo. I'm new enough to TS that I don't know whose issue that is to fix, but this issue seems to claim this error involves not exporting the superclass and nothing I've done fixes that. Everything else in my file compiles, and this only fails when I try to export my class and use its declarations.

Thanks.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 13, 2016

@ndarilek can you file a new issue and provide a self containing repro. from a cursory look this looks like a bug, but i will have to look at the code to know for sure.

@nahushf
Copy link

nahushf commented Sep 26, 2016

Why does this error occur in react when used with typescript?
I have a component TestComponent which uses an interface to define its props.

export interface ITest {
    name?: string;
}

class TestComponent extends React.Component<ITest, void> {
    render(): JSX.Element {
        return(
            <div></div>
        );
    }
}
export {TestComponent};

and the generated declaration file is:

export interface ITest {
    name?: string;
}
declare class TestComponent extends React.Component<ITest, void> {
    render(): JSX.Element;
}
export { TestComponent };

Here I don't see why the interface needs to be exported at all . The required interface i.e. ITest in the above example is being generated anyway in the declaration file and it is only being used in the TestComponent. So there should be no need of exporting the interface

Also what is the difference between exporting the interface when it is declared i.e.

export interface ITest {}

and exporting it as

interface ITest {}
export {ITest}

The latter seems to throw the has or is using a private name error too.

damyanpetev added a commit to damyanpetev/zero-blocks that referenced this issue Sep 26, 2016
Exporting BaseInput as bundling TS build throws TS4020, see microsoft/TypeScript#6307
@olavorn
Copy link

olavorn commented Dec 11, 2016

The following code:

class Test {
constructor(public someting: any){}
}

export let t = new Test("some thing");
produces the following error:

Exported variable 't' has or is using private name 'Test'.

try this:
export let t = <any>new Test("some thing");

Works if you don't bother taking the Test type to your d.ts declarations.

@aMarCruz
Copy link

I'm new to TypeScript, but using v2.3.4 this works for me:

// pluggable-parsers.ts

interface IParserTree {
  [index: string]: IParserNode
}

interface IParserNode {
  [index: string]: IPluggableParser
}

export interface IPluggableParser {
  (source: string, options: object): { code: string, map: string | object }
}

export interface IPluggableParsers {
  require(parserPath: string, throwErrors: true): IPluggableParser | never
  require(parserPath: string, throwErrors?: boolean): IPluggableParser | null
}

class PluggableParsers implements IPluggableParsers {

  private readonly _parsers: IParserTree

  constructor() {
    this._parsers = {
      html: {},
      css: {},
      js: {}
    }
  }

  require(parserPath: string, throwErrors?: boolean) {
    const [root, name] = parserPath.split('.')
    const parser = this._parsers[root] && this._parsers[root][name] || null

    if (!parser && throwErrors) {
      throw new Error(`Parser ${parserPath} not found.`)
    }

    return parser
  }
}

export default new PluggableParsers() as IPluggableParsers

I got this // pluggable-parsers.d.ts

export interface IPluggableParser {
    (source: string, options: object): {
        code: string;
        map: string | object;
    };
}
export interface IPluggableParsers {
    require(parserPath: string, throwErrors: true): IPluggableParser | never;
    require(parserPath: string, throwErrors?: boolean): IPluggableParser | null;
}
declare const _default: IPluggableParsers;
export default _default;

...and this pluggable-parsers.js

var PluggableParsers = (function () {
    function PluggableParsers() {
        this._parsers = {
            html: {},
            css: {},
            js: {}
        };
    }
    PluggableParsers.prototype.require = function (parserPath, throwErrors) {
        var _a = parserPath.split('.'), root = _a[0], name = _a[1];
        var parser = this._parsers[root] && this._parsers[root][name] || null;
        if (!parser && throwErrors) {
            throw new Error("Parser " + parserPath + " not found.");
        }
        return parser;
    };
    return PluggableParsers;
}());
export default new PluggableParsers();

Transpiled and ready to be processed by Rollup.

@cameron-martin
Copy link

cameron-martin commented Sep 25, 2017

Why can't Test be put in the d.ts file, but not exported? E.g.

class Test {
    constructor(public someting: any);
}

export let t: Test;

This behaviour surprised me when generating declaration files for react classes - it requires you to export the State interface, which should be an implementation detail, not in the public interface of the module.

@dontsave
Copy link

dontsave commented Oct 14, 2017

I'm curious why every interface must be exported if referenced by any other exported object as well. With large react-redux projects it leads to an enormous proliferation of exported interfaces, each of which must have their own unique names.

@rohitkandhal
Copy link

Came here to point that you might get this error because of in correct order in export statement. I was getting ` error for following code:

error TS4025: Exported variable 'Error' has or is using private name 'ErrorProps'.

const Error = (props: ErrorProps): JSX.Element => {
  return (
    <div>
      <img src={props.icon} />
      <span>{props.errorCode}</span>
    </div>
  );
};

export {
  Error,
  ErrorProps
};

Solution Need to change the export order

export {
  ErrorProps,
  Error
};

@nichtverstehen
Copy link

Should this issue be reopened?

It seems that it affects many people and the workaround impacts public interfaces of modules which is not ideal. On the other hand, apparently, fixing this shouldn't require major changes to the emitted declarations. The referenced unexported symbols do already get declared.

Minimal reproduction:

# a.ts

interface A {
  m: string;
}

export function f(a: A): string {
  return a.m;
}
$ tsc -d a.ts
a.ts(5,22): error TS4078: Parameter 'a' of exported function has or
is using private name 'A'.

Expected:

# a.d.ts

interface A {
    m: string;
}

export function f(a: A): string {
  return a.m;
}

Indeed, a user of a should be able to call f({m: "hello"}) (and typecheck against the unexported declaration), but not necessarily refer to the interface A directly by name.

Note that unexported types do get written to declaration files. E.g. if a.ts has only interface A {}, a.d.ts gets the unexported declaration interface A {}.

mhegazy pushed a commit to DefinitelyTyped/DefinitelyTyped that referenced this issue Apr 14, 2018
* Re-type `helper` from @ember/component/helper

Previous typing caused an error about using private name `Ember.Helper`
when generating declaration files.

Fortunately, the previous typings were incorrect anyway, so we can
remove the reference to `Ember.Helper` and thus fix the issue.

Relevant links:
* microsoft/TypeScript#5711
* microsoft/TypeScript#6307
* https://www.emberjs.com/api/ember/2.18/functions/@ember%2Fcomponent%2Fhelper/helper
* https://github.com/emberjs/ember.js/blob/v2.18.2/packages/ember-glimmer/lib/helper.ts#L120

* Add test for `helper` from @ember/component/helper
@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Canonical This issue contains a lengthy and complete description of a particular problem, solution, or design Docs The issue relates to how you learn TypeScript Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests