Skip to content

[Design Spec] ESNext import() #14495

Closed
Closed
@yuit

Description

@yuit

import(specifier) is a newly proposed syntax for dynamically module loading. import(specifier) takes an assignment expression as an input (Note: unlike ES6 static import which only allow string literal as module specifier) and returns a promise of module namespace object.

The full proposal can be found here
Original issue: #12364

This issue will discuss design proposal for implementing import(): parsing, type-checking, and emitting.

The proposal will NOT include "module namespace object" type and expressing the shape of the loaded module (To be able to express such type will allow users to cast the result instead of "any" to be what they expected at runtime)...The issue will be discussed and implemented separately.

Parsing
import(specifier) will be parsed as CallExpression. and specifier will be parsed as AssignmentExpression

Error

  • Error if the module flag is ES2015.

  • Error if specifier is not assignable to string type

Type-checking

  • specifier is type checked as string type. (Clarification: the only limitation for specifier in original proposal is that it can called toString())

  • The return of import(specifier) will be as following
    -- if known module can be resolved from specifier, then we return Promise of module namespace object
    -- if not known module, then we return Promise of any. This will give an error in noImplicitAny mode and import() is used as an expression After offline discussion with @mhegazy @bowdenk7 @DanielRosenwasser, we think reporting an error without providing a way to easily get out of it (see [Design] Syntax to represent module namespace object in dynamic import #14844 for more detail) is undesirable. By casting to Promise<any> to satisfy the compiler will not provide users any benefit and arguably is a drawback because if in the future, there is a way to type the module easily, upgrading to use such syntax will not be convenient. Therefore, we will not issue an noImplicitAny error with this feature but with [Design] Syntax to represent module namespace object in dynamic import #14844 instead.

  • We will use existed module resolution logic to try to figure out the module of the dynamic import.

Emit
Emit for each different module kind emit is outlined below

import('blah');
  • Node
Promise.resolve().then(() => require('blah'));
  • AMD
define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    new Promise(resolve => require(['blah'], resolve));
});
  • UMD
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    require.length === 1 ?
        /*CommonJs Require*/ Promise.resolve().then(() => require('blah'));
        /*Amd Require*/ new Promise(resolve => require(['blah'], resolve));
});
System.register([], function (_export, _context) {
  return {
    setters: [],
    execute: () => {
      _context.import('dynamic');
    }
  };
});
  • ES2018 new value
import('blah')

Metadata

Metadata

Assignees

Labels

CommittedThe team has roadmapped this issueES NextNew featurers for ECMAScript (a.k.a. ESNext)FixedA 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