The issue arises from the tutorial's utilization of invalid ESM -> CommonJS interop. It is recommended to use import $ from jQuery;
instead. The usage of a namespace import (* as
) in ECMAScript is considered invalid.
In short: follow these steps
import $ from 'jquery';
import 'bootstrap-daterangepicker';
and ensure to set --allowSyntheticDefaultImports
(set
"allowSyntheticDefaultImports": true
under
"compilerOptions"
) to ensure TypeScript properly typechecks code using the synthesized default import.
I have also left a comment regarding this matter on the article.
More Details:
Essentially, according to the ECMASCript specification, calling Module Namespace Objects as functions is prohibited. When using the syntax
import * as imported from 'some-module';
a module namespace object named imported
is created. This object exposes each export of the specified module for qualified access like imported.a
, where a
is exported by 'some-module'
. However, in AMD or CommonJS modules that only export a single value, it is common practice to export this value as the module itself. This is typically portrayed as
// AMD
define(function () {
const $ = {...}; // jquery implementation
return $;
});
Or
// CommonJS
const $ = {...}; // jquery implementation
module.exports = $;
The value returned by define
or assigned to module.exports
represents the module itself.
To import such an export, one would usually write
// AMD
define(["jquery"], function ($) {
$('div').text('set via jQuery');
});
Or
// CommonJS
const $ = require("jquery");
$('div').text('set via jQuery');
Contrastingly, when dealing with a named export, the typical representation involves
// AMD
define(function () {
const $ = {...}; // jquery implementation
return {$};
});
Or
// CommonJS
const $ = {...}; // jquery implementation
module.exports.$ = $;
To import such an export, one would generally write
// AMD
define(["jquery"], function ($) {
$.$('div').text('set via jQuery');
});
Or
// CommonJS
const $ = require("jquery");
$.$('div').text('set via jQuery');
Returning to the ES Module realm, the * as
syntax combines named exported bindings into an object for dotted (.
) access.
Unlike AMD and CommonJS modules, in an ES Module everything exported must be done so under a specific name.
However, the simplicity of exporting/importing a single value representing the module itself is still offered in ES Modules through the default
export/import syntax, like so
// ESM
const something = {...};
export default $;
And is normally consumed as
// ESM
import $ from 'some-module';
This concept closely resembles assigning to module.exports
or returning a single value from define
, however, default
is not anonymous; it is explicitly an export named default
.
The question then arises, when faced with an AMD or CommonJS module that exports a value as the module itself (often using one of the aforementioned patterns), how can we import it into an ES Module? Since require
is unavailable in this scenario and importing unnamed values is not permitted, interoperability ensures that the value of module.exports
or what is returned by define
is accessible as the default
export. While this method has its challenges, it allows us to execute
import $ from 'jquery';
This approach works because default
, which is essentially an export named default
, can be called. A namespace cannot be invoked as such.
Regrettably, due to fluctuations within the ES Module specifications, uncertainty surrounding the establishment of an interoperability mechanism, and various historical factors, TypeScript has historically followed a different route, interpreting
import * as imported from 'some-module';
to mean
const imported = require('some-module');
at the type level. Additionally, it does not automatically map values exported as AMD and CommonJS modules to the default
, resulting in potential runtime failures even if the syntax appears correct.
However, there are plans for TypeScript to address this discrepancy.
In the meantime, utilizing a module interop-aware tool like SystemJS or Webpack 3 enables users to correctly employ
import imported from 'some-module';
in TypeScript today.
Remember to enable the --allowSyntheticDefaultImports
compiler option to ensure proper typechecking of this syntax against AMD or CommonJS modules.