Suggestion
🔍 Search Terms
es esm module cjs commonjs type import moduleResolution node16 nodenext
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
Allow CommonJS modules to import types from ES Modules without an async import() if import types is specified.
With moduleResolution: "node16" enabled, we now get this very helpful error message when importing an ES Module from a CommonJS module (thank you!):
// Error: Module 'my-es-module' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
import MyModule from 'my-es-module';
However, it is often the case that module will export a types API as well as a runtime API. Sometimes, we only want to import the types from a package. Typescript has the very helpful import type directive to acommodate this use case. However, if we want to import the types from an ES Module, we still get the following error:
// Error: Module 'my-es-module' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
import type { MyTypeDefinition } from 'my-es-module';
Because import types are stripped from runtime code, there is no need to throw this error.
📃 Motivating Example
Because this error is thrown, it forces us to add an unnecessary async import somewhere in our file, causing non-ergonomic development at best, and unnecessary runtime complexity at worst.
Consider:
// ES Module "my-es-module"
export type MyTemplateString = `${string}-custom-string`;
function myFunction() {
const tmp = await import('my-ex-module');
const custom: tmp.MyTemplateString = 'contrived-custom-string';
return custom;
}
It also (very unfortunately) makes it simply impossible to create and re-export derivative types from a module like this:
import type { MyTemplateString } from 'my-es-module';
export interface MyInterfaceDefinition {
type: MyTemplateString | null;
value: string;
}
💻 Use Cases
See above motivating example. I'm currently using // @ts-expect-error to get past this, but would be great not to! This error should obviously still throw if importsNotUsedAsValues is set to preserve.
Suggestion
🔍 Search Terms
es esm module cjs commonjs type import moduleResolution node16 nodenext
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
Allow CommonJS modules to import types from ES Modules without an
async import()ifimport typesis specified.With
moduleResolution: "node16"enabled, we now get this very helpful error message when importing an ES Module from a CommonJS module (thank you!):However, it is often the case that module will export a types API as well as a runtime API. Sometimes, we only want to import the types from a package. Typescript has the very helpful
import typedirective to acommodate this use case. However, if we want to import the types from an ES Module, we still get the following error:Because
import types are stripped from runtime code, there is no need to throw this error.📃 Motivating Example
Because this error is thrown, it forces us to add an unnecessary async import somewhere in our file, causing non-ergonomic development at best, and unnecessary runtime complexity at worst.
Consider:
It also (very unfortunately) makes it simply impossible to create and re-export derivative types from a module like this:
💻 Use Cases
See above motivating example. I'm currently using
// @ts-expect-errorto get past this, but would be great not to! This error should obviously still throw ifimportsNotUsedAsValuesis set topreserve.