Skip to content

Cannot use the BindingIdentifier of an ambient module import as type annotation #9076

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

Closed
tommahieu opened this issue Jun 10, 2016 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@tommahieu
Copy link

tommahieu commented Jun 10, 2016

(I posted this on StackOverflow first, but got no response. So either this is a hard question or a stupid one, but I'm too new at TypeScript to be able to judge. So please excuse me if the latter case applies).

I am writing a TypeScript Type definition for a pretty large (800+ files) AMD JavaScript library. Below you can see a snippet:

declare namespace myjslib {
  namespace shape {
    interface Shape {
      contains(p: Point): boolean;
    }

    class Point implements Shape {
      constructor(x: number, y: number);
      contains(p: Point): boolean;
    }

    class Circle implements Shape {
      constructor(p: Point, radius: number);
      contains(p: Point): boolean;
    }
  }
}

declare module "myjslib/shape/Point" {
  export = myjslib.shape.Point;
}

declare module "myjslib/shape/Circle" {
  export = myjslib.shape.Circle;
}

I have defined types in namespaces. (note that myjslib is not the real name of the library :)):

  • The namespaces pretty much correspond with the module IDs in the AMD library, as you can see from the module declarations.
  • I decided to put these classes into namespaces to avoid clashes (cfr.
    https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html). Class names like Point and Circle are likely to clash if my library is combined with other JavaScript libraries.

I then try to write a TypeScript application that depends on this type definition file:

/// <reference path="./myjslib.d.ts" />
import Point = require("myjslib/shape/Point");
import Circle = require("myjslib/shape/Circle");

import Circ = myjslib.shape.Circle;

let c1 = new Circle(new Point(1,3), 20);
let c2: Circle;
let c3: myjslib.shape.Circle;
let c4: Circ;

c1.contains(new Point(5,6));
c2 = c1;
c3 = c1;
c4 = c1;

When compiling this typescript file, the correct JavaScript code is generated: the output is valid AMD, can be loaded with an off the shelf AMD module loader, and can be optimized into a single JavaScript file, etc.

However, the TypeScript compiler (I am currently using version 1.8.10) generates an error at the declaration of the c2 variable:

>tsc --module amd app.ts
app.ts(8,9): error TS2304: Cannot find name 'Circle'.

Apparently, it is possible to refer to the imported Circle to create a circle instance. The import statement works as you have access to the Circle constructor. However, Circle cannot be used as a type annotation when declaring a variable of that type. What does work however is using the fully qualified name of the type: the compiler does not complain about the c3 declaration, so the typescript definition file is found and used by the compiler. Also, if I create an alias Circ, The type system works like a charm (declaration of c4).

It was my understanding that the import Circle = require("myjslib/shape/Circle") statement created a local alias for the Circle entity but this does not appear to be the case.

So in conclusion: I am currently writing code where I have to use the import BindingIdentifier to create instances of a particular class, but I have to use the fully qualified type name if I want to declare variables of that class. This makes writing code pretty confusing (and verbose). Is there any way around this? Is this the expected behavior, or am I running into a TypeScript compiler bug?

@mhegazy
Copy link
Contributor

mhegazy commented Jun 10, 2016

the issue is in the use of export =. this is rather subtle, and it should be fixed on the compiler side at some point. the issue is export=<identifier> exports all meaning of an identifier, where as export=<dotted name> does not. see #4325.

so if you rewrote your code as:

declare module "myjslib/shape/Point" {
   import _point =  myjslib.shape.Point
    export =_point;
}

it should work as expected.

@mhegazy mhegazy closed this as completed Jun 10, 2016
@mhegazy mhegazy added the Duplicate An existing issue was already created label Jun 10, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Jun 10, 2016

closing in favor of #4325.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

2 participants