Typescript: Object detection for "Exported variable `` has or is using name `` from external module"

Created on 4 Dec 2015  路  16Comments  路  Source: microsoft/TypeScript

With the following structure:

  • node_modules/a/default.d.ts containing a typing and a function
  • node_modules/a/package.json containing a typings field to default.d.ts
  • src/default.ts' re-exporting everything from a and exporting new functions
  • src/newFunctions.ts using the src/default.ts

You get "exported variable has or is using name from external module" errors when using an object:

import * as b from './default';

// Bug: This does the same thing, but in an object. It should still compile fine, but it doesn't.
export let wrap = {
  findPersonById: function(id: number): b.IPerson {
    return b.findPersonById(id);
  }
}

However, when you don't use an object the functionality works as expected:

import * as b from './default';

// OK: Expected behavior. Since `b` exports everything from `a`, exporting `b.IPerson` is fine.
export function wrapFindPersonById(id: number): b.IPerson {
  return b.findPersonById(123);
}

Using 1.8.0-dev.20151204. Full repo https://github.com/Deathspike/typescript-reference-bug-example/

Bug Declaration Emit Fixed

Most helpful comment

Would love to see this one addressed, a bit pesky.

All 16 comments

A simplified repro is available in https://github.com/Microsoft/TypeScript/issues/8612

8612 is what I'm trying to do. What is the difficulty of fixing this issue? Or, is there any way to work around this so that all the exports from a group of files can be imported into the same namespace?

Aha. All I have to do is reference the original file, even if I don't use that reference. So, before, I had this:

////// model/index.ts

export { Team } from './Team'
export { Game } from './Game'
export { Score } from './Score'
////// action/index.ts

import * as model from '../model'

// This declaration produces the "cannot be named" error
export const getTeam = (teamId: string): model.Team => {
    // ...
}

But if I add import * as __Team from '../model/Team' to action/index.ts I'm error-free:

////// action/index.ts

import * as model from '../model'
import * as __Team from '../model/Team' // Throwaway reference

// No more error!
export const getTeam = (teamId: string): model.Team => {
    // ...
}

It's less than ideal, but at least I can keep my model.Team format.

if setting compilerOptions.declaration to false, there will be no more error!

Right... but that's not what we want. It should work fine whether we generate declaration files or not. In my case, I need the declaration files to be generated, and this workaround has proven successful, but quite the pain.

Any ETA on this? Thanks!

Would love to see this one addressed, a bit pesky.

At the very least, as a shorter-term solution, it'd be nice to see a compiler option that allows definition files to be generated, with definitions that "cannot be named" simply being omitted, or replaced with any. I want definition files, but I find it annoying that one my two co-dependent projects keeps insisting that the definitions in the other can't be named, like some kind of low-ranking bureaucrat who refuses to think beyond the literal wording in his employee manual.

I've just started to move shared code from your /shared project folder to separate module and stuck with this issue. Very sad !

In case you missed it, there is a workaround to this issue if you're stuck. I posted it above.

@robyoder - I'm running into this same issue but with a module that's not mine. Specifically - express.

import * as express from "express";

let router = express.Router();

router.use(...);

export = router;

recreates this issue for router but I can't simply say import * as Router from "express/Router" because that doesn't exist. Is there a different workaround for this case or am I doing something wrong?

Thanks!

Oh and I found a solution here - https://github.com/Microsoft/TypeScript/issues/9944#issuecomment-288776200

@theigor right, that's the solution. You could still use it as express.Router() though. All TS needs is the name to be imported. So you'd just add

import { Router } from "express";

but you don't actually need to change any other code (to use Router directly).

@weswigham your fix is good for explicit re-exports like this:

export { Team } from "./Team";

but TS still fails when using a star export like this:

export * from "./Team";

I've pushed a simple project showing this issue: https://github.com/robyoder/tsctest

@robyoder Wanna open a new issue with the new repro? The reason for that failure is different from the underlying reason the named reexports were failing.

@weswigham done: #20657

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgrieder picture bgrieder  路  3Comments

jbondc picture jbondc  路  3Comments

remojansen picture remojansen  路  3Comments

siddjain picture siddjain  路  3Comments

wmaurer picture wmaurer  路  3Comments