Description
Edit 2/29: Update proposal based on design changes; moved 'Solution' to top since most people viewing this are familiar with the problems
Solution
Support a "native UMD" declaration form that allows for a global var to be of the type of a module.
A global module export declaration has the syntax:
export as namespace id;
where id
is any Identifier.
This is only legal as a top-level declaration a .d.ts
file containing other top-level export
declarations (e.g. export function
, export var
, export =
, etc.). Multiple of these declarations may appear in the same file so long as they supply different identifiers.
When the containing file is imported through import
syntax, the declaration has no effect.
When the containing file is added to the compilation via a /// <reference
directive or by being a top-level file provided to the compiler (e.g. on the commandline, or as part of tsconfig.json
's files
list), the supplied identifier[s] are added to the global scope of the program. The type of these identifiers is the type of the module object of the file in which they were declared.
These declarations may engage in module merging, though this should probably be discouraged somehow.
Example
my-lib.d.ts
export function doThing(): string;
export function doTheOtherThing(): void;
export as namespace myLib;
globalConsumer.ts
/// <reference path="my-lib.d.ts" />
myLib.doThing();
importConsumer.ts
import * as m from './myLib';
m.doTheOtherThing();
Problem
Many definition flies are written like this:
declare var Promise: {
// some stuff here
}
declare module 'bluebird' {
export = Promise;
}
Symptoms
This is bad for three reasons:
- We can't find this file from normal module resolution, so it has to get into the compilation context through a 'reference' mechanism
- This pattern can't handle the case where you have two versions of
'bluebird'
because there is no path with which to disambiguate - People who are using the module version still get global scope pollution and might accidently use the global names when they meant to use an import name
Root Cause
The reason people do this (define globals, then export =
from an ambient module declaration) is that the *reverse * (define a module, then declare a var with that module's type) is impossible.