Description
There are some use cases that use tsc to emit ESModule that runs in the browser directly. Currently, TypeScript is not friendly to browser style import environment like browser and deno.
There are some main problems when using TypeScript in those environments:
- 1. Import
.ts
,.tsx
file is a type error (PR: New --emitExtension and --noImplicitExtensionName compiler options #35148) - 2. Emitted code does not contain the
.js
extension name (PR: New --emitExtension and --noImplicitExtensionName compiler options #35148) - 3. Can not emit file with
.mjs
extension name (PR: New --emitExtension and --noImplicitExtensionName compiler options #35148) - 4. Can not handle the type resolution for URI import finely
- 5.
Should treat folder import (import './src'
=>import './src/index.ts'
) as type error in some environments - 6. Should treat import without extension name (
import './src'
=>import './src.ts'
) as type error in some environments
1. Import .ts
, .tsx
file is a type error
Related issues: #30076
This happens in the deno. Deno will not try to resolve implicit extension name when handling imports.
import "./file";
This import is invalid for deno and browser.
In browser we have to write import "./file.js";
which is valid in the type checker.
In deno we have to write import "./file.ts";
which is invalid in the type checker. TypeScript reports An import path cannot end with a '.ts' extension. Consider importing './file' instead
#35148 introduce a change that importing a .ts
or a .tsx
file is no longer a type error. Importing .d.ts
is still a type error.
2. Emitted code does not contain the .js
extension name
Related issues: #16577, #30076
When tsc is used to emit ESModule for browsers, the extname is not added. Now one can write import './file.js'
to refer to file.ts
, that behavior is strange in the semantic.
#35148 introduce a new compilerOption called --emitExtension
. With this option, TypeScript will replace the .ts
or .tsx
extension name for relative imports.
import "./file";
import "./file2.ts";
import "./file3.tsx";
// with --emitExtension .mjs
// result to
import "./file";
import "./file2.mjs";
import "./file3.mjs";
3. Can not emit file with .mjs
extension name
Related issues: #30076, #18442
In Node.js, there is a discussion about how to migrate to ES Module, a solution requires all ES Module files have to have a .mjs
extname. There is no way to emit such code by tsc now.
#35148 introduce a new compilerOption called --emitExtension
. With this option, TypeScript will emit the code with the specified extension name.
There are lots of different solutions that requires different extension name for js file like .es
, .mjs
, .es.js
so TypeScript maybe should not restrict the possible value of --emitExtension
with a enum.
--emitExtension
must start with.
and can not be.d.ts
when using
--jsx preserve
,--emitExtension
must be.jsx
src
index.ts
index2.ts
index3.ts
# with --emitExtension .mjs
# will emit
dist
index.mjs
index2.mjs
index3.mjs
4. Can not handle the type resolution for URI import finely
Related issues: #28985, #19942
In browser and deno, import from a "package" is different from the node style.
// browser
import lodash from "https://unpkg.com/[email protected]/lodash.js";
// deno
import { serve } from "https://deno.land/[email protected]/http/server.ts";
Currently there is no way to let TypeScript automatically map the URI to another place like @types/*
or $DENO_DIR/deps/https/deno.land/*
The current path
can map a simple pattern of import module specifier to another place, but in the URI style import, a more flexible way to map the URI is required.
Proposal
(maybe add a new moduleResolution: browser
)
Add a new uriPaths
that allows to map from a RegExp to a local path. It will NOT effect the emitted code. Just a way to find the type definition for those URIs.
Example:
This rule map https://unpkg.com/[email protected]/lodash.js to @types/lodash-es
Map https://deno.land/[email protected]/http/server.ts to $DENO_DIR/deps/https/deno.land/std/http/server.ts
.
$DENO_DIR is an environment variable.
By default, on Windows, it's ~\AppData\Local\deno\deps\https\deno.land\std\http\server.ts
.
By default on Linux, it is ~/.deno/deps/https/deno.land/std/http/server.ts
.
5. Should treat folder import (import './src'
=> import './src/index.ts'
) as type error in some environments
import './src'
=> import './src/index.ts'
) as type error in some environments*: Folder import is supported only in moduleResolution: node
The folder import is only supported in Node.js and some bundle tool, browsers and deno doesn't support it.
Proposal
Add a flag --noFolderImport
to ban the folder import.
6. Should treat import without extension name (import './src'
=> import './src.ts'
) as type error in some environments
The implicit extension name is only supported in Node.js and some bundle tool, browsers and deno doesn't support it.
Proposal
Add a flag --noImplicitExtensionName
to ban the implicit import.
There are 6 problems when tsc is used with browser native ESModule or deno. The first one to the third one is fixed by #35148.
I have interest to do the 4 to 6. But I should make sure TypeScript team will accept those.