Imports in a reference file.

Topics: General, Language Specification
Aug 28, 2013 at 4:13 AM
Just a simple question.

In my work we are using commonjs, however in our main file (which is javascript) we are including certain typescript files as global. I was wondering if there was an easy way for me to model that using .d.ts files?

The following is an example of how I thought I could do it.

Typescript file foo.ts:
export = function Foo (bar: string) {
    console.log(bar);
}
And a constants.d.ts file:
declare import Foo = require("foo");
Then, in my working file, I could put:
/// <reference path="constants.d.ts" />
Foo("Hello!");
Knowing that Foo had already been required and was available globally.
Oct 1, 2013 at 4:28 AM
Shameless bump.
Oct 1, 2013 at 3:51 PM
IMO no one has bothered to answer this question because it's not very clearly spelled out, and furthermore appears to have a few errors in the posted samples.

Did you mean that
export function Foo(bar: string) {
    console.log(bar);
}
generates foo.d.ts
export declare function Foo(bar: string): void;
And this cannot be referenced in another .ts file?

It appears that when a ".d.ts" contains an export keyword it cannot be referenced in another file (via <reference>), for example this declarations file cannot be referenced:
declare class Bar { }
declare function Foo2(bar: string): void;
export declare function Foo(bar: string): void;
This works:
declare class Bar { }
declare function Foo2(bar: string): void;
// export declare function Foo(bar: string): void;
This may well be a bug.
Developer
Oct 1, 2013 at 6:43 PM
Edited Oct 1, 2013 at 6:43 PM
@nabog: that does look odd, copied to a work item here
Developer
Oct 2, 2013 at 12:56 AM
To answer the original question: No, that isn't possible.

When a source file contains 'export' declarations at top-level it is considered an external module (regardless of how it is subsequently referenced). External modules should always be imported with 'import' declarations, otherwise you won't have an alias through which you can reference the contents of the external module.

It is not meaningful to use /// <reference> with an external module. It will include the module in the compilation, but unless you also 'import' it there is no way to reference it.
Oct 4, 2013 at 2:17 AM
Thank you for the feedback - I hadn't realised that the question was ambiguous.
I'll try and clear it up now.

Say I have a .ts file which is imported in one project (we'll call it project A) as such:

Example utilities.ts file:
export function stripCommentsFromJSONString() {
    //Code Here.
}

export function safeEval() {
    //Code Here.
}
Then, in that project B I reference the file as such (using commonjs):
import Utilities = require("utilities");

//... stuff
var JSONobj = JSON.parse(Utilities.stripCommentsFromJSONString(jsonstring));
//... stuff
Then in project C (which is also using commonjs) a number of files have been imported and declared as
global for use in other files, these are specified in a file called globalconstants.d.ts:
This is the suggestion - and is not currently supported.
/// <reference path="lib/node.d.ts" />
declare var Utilities = import("utilities");
declare var Networking = import("networking");
And then in any arbitary file in project C I can include globalconstants.d.ts and the variables available from utilities.ts are now available in the Utilities variable declared in globalconstants.d.ts:

e.g. in importjsondata.ts
/// <reference path="lib/projecta/globalconstants.d.ts" />

//... CODE - & replacer declaration.

var JSONobj = JSON.parse(Utilities.stripCommentsFromJSONString(jsonstring), replacer);

//... more code
The request is the ability to use an import statement coupled with a declare statement in a .d.ts file to represent a commonjs file that has been previously imported into the current scope.

I hope that's more clear :)
Oct 4, 2013 at 6:47 PM
Your final words here highlight the problem, namely "...to represent a commonjs file that has been previously imported into the current scope"

In a CommonJS module system there is no way to "previously import" something into the current scope. The scope is the module, and the current module is equal to the JavaScript source file, which is equal to a source TypeScript file (as we have no multi-file external module compilation). Thus if you want a module to be available for use, you need to explicitly import it in the source file that will reference it.

Anders last 2 sentences are still highly relevant here, namely:

"External modules should always be imported with 'import' declarations, otherwise you won't have an alias through which you can reference the contents of the external module."

"It is not meaningful to use /// <reference> with an external module. It will include the module in the compilation, but unless you also 'import' it there is no way to reference it."
Oct 6, 2013 at 7:12 AM
There is a way that lies in the way that javascript (the language) works, which is to declare a global var (or assign a module to a variable that has not been declared).

For example (imagine a bootstrapper file):
Utilities = require('./utilities');
Networking = require("./networking");
require("./application");
Since neither Utilities or Networking were declared before they were required, they are now available as globals in the /application file (and any further files). There can be many or few of these global constants.

I was hoping that the ability to use frameworks (made in CommonJS) or external files in such a manner would be supported, as it would help to find errors when those global constants change - but I can understand if you decide against supporting this style of using JavaScript.
Mar 27, 2014 at 2:41 AM
Hello, I thought I'd try and get some more feedback on this topic now that TypeScript 1.0 (beta) is out.