Typescript: “import b from './b.ts'” is valid JavaScript, but invalid TypeScript

Created on 13 May 2020  Â·  8Comments  Â·  Source: microsoft/TypeScript

This has been already mentioned several times on different places, that tsc shall accept import b from './b.ts' as valid, despite the .ts exception, but the argument, that the input is valid JavaScript, but invalid TypeScript has never been raised.

Copied from https://github.com/microsoft/TypeScript/pull/35148#issuecomment-628015652:

I want to use TypeScript to check the types. But to compile the code fast I want to strip the types with @babel/preset-typescript.

When I write in some of my files import x from ./x.ts tsc 3.9.2 says: “An import path cannot end with a .ts extension”, but rollup/@rollup/plugin-babel/@babel-preset-typescript eat the input happy.

When I write instead import x from ./x.js, typescript does eat the input, but rollup/@rollup/plugin-babel/@babel/preset-typescript cannot find the file. Likewise, when I use import x from ./x.

This code, a.js:

import b from './b.ts'
console.log(b)

b.ts:

export default 'blub'

is valid JavaScript, it just does not work in Node.JS, as the latter refuses to accept .ts file extension.

But when b.ts is delivered with the correct mime type, then this works:

<html>
  <body><script type='module' src='./a.js'></script>
  Firefox and Epiphany print “blub” on the console.</body>
</html>

Demonstration: https://mail.aegee.org/dpa/35148/file.html

To sum up,

import b from './b.ts'

is valid JavaScript, and tsc refuses to accept valid JavaScript.

Question

Most helpful comment

Well, this is not a question.

All 8 comments

For @rollup/plugin-babel + @babel/preset-typescript to work, I just found that I have

  • to use the syntax import b from './b' when I mean b.ts, and
  • to pass extensions: ['.ts', '.js'] to both @rollup/plugin-node-resolve and @rollup/plugin-babel

Since writing import b from './b' when I mean from ./b.ts is not valid ES6-JavaScript logic, it is also not intuitive.

For updating the documentation of @rollup/plugin-babel how to work with TypeScript imports I filled https://github.com/rollup/plugins/issues/393 .

TypeScript is not obligated to issue zero errors on all JavaScript input files, otherwise no one would use it. See other issues on allowing module resolution to find .ts files.

I had to search a lot to find a workaround: import ./b when I mean import ./b.tswith rollup-babel-typescript. But this then compiles in both just typescript or just rollup-babel-transform-typescript. However the output of typescript 3.9 is not executable by NodeJS, when the target is ES2020.

Typescript also reads k.tswhen one writes import ./k.js.

It will be just simpler for everybody, if import in ES6-terms and in TypeScript terms act the same way for local files (except for import type ...). Refusing import b from './b.ts' is not suitable to prevent the user from doing errors, so there is no point to refuse it.

https://www.typescriptlang.org/docs/handbook/module-resolution.html talks in the “Node resolution strategy” about require("./moduleB") that it tries to open ./moduleB.js. But it does not say that import ./moduleB does not work with --target ES2020, while import ./moduleB.js and require("./moduleB") do work:

With a.ts:

import b from './b'
console.log(b)

b.ts:

export default 'uuuu'

tsc --target es2020 a.ts produces:

a.js:
import b from "./b"
console.log(b)

b.js:
export default "uuu"

When package.json contains “type”:"module", node a.js prints error, that it cannot find module ./b.

So with import b from "./b" tsc --target es2020 emits import b from './b' which is wrong, as NodeJS expects import b from './b.js. So I have to provide as input import b from './b.js' when I mean import from ./b.ts

https://www.typescriptlang.org/docs/handbook/module-resolution.html says nothing about this. And there are more than one typescript language interpreters. In order to make them compatible/interchangable, either import works with relative imports at least in the same way, as ES6 import does, or it needs very clear documentation, that to import b.js, one has to write in ES6 import ./b.js, but in Typescript the user has to write the same, when the target is ES2020, but can also write import ./b for lower targets. In particular in TS for ES2020 one has to write now import ./b.js when in fact ./b.ts is meant, but rollup-babel-transform-typescript are not that smart: they cannot find b.js, because the file is not there.

So TS shall accept import './b.ts' and emit import './b.js'.

So TS shall accept import './b.ts' and emit import './b.js'.

We don't rewrite import paths. See https://github.com/microsoft/TypeScript/issues/35589

That link says 'This is the fundamental promise of TypeScript: You can take some JavaScript code, put it in a TypeScript file, and it means the same thing meant before.' which contradicts the subject of this ticket.

TS needs whole program knowledge or file extensions-based conclusions get abandoned. Then the only thing for import to clarify is: is that thing, without rewriting, an existing file, or an existing directory?

All that said, the .ts extension shall disappear, typescript input files get emacs-like headers, and tsc makes sure, that the input and output directories are distinct. Then no filename rewritings happen, the whole output is moved somewhere else.

Or the extension .ts stays, but the javascript engine starts accepting it somehow (as browsers do now based on mime type).

But when the import means a ts file, then having .ts after the import cannot be wrong (as it is now).

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

Well, this is not a question.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kimamula picture kimamula  Â·  147Comments

tenry92 picture tenry92  Â·  146Comments

rwyborn picture rwyborn  Â·  210Comments

OliverJAsh picture OliverJAsh  Â·  242Comments

chanon picture chanon  Â·  138Comments