Skip to content

Built-in support for UMD module definitions #7125

Closed
@RyanCavanaugh

Description

@RyanCavanaugh

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:

  1. We can't find this file from normal module resolution, so it has to get into the compilation context through a 'reference' mechanism
  2. This pattern can't handle the case where you have two versions of 'bluebird' because there is no path with which to disambiguate
  3. 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.

Metadata

Metadata

Assignees

Labels

@typesRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedCommittedThe team has roadmapped this issueFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions