Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
dilyanpalauzov opened this issue May 13, 2020 · 8 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@dilyanpalauzov
Copy link

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 #35148 (comment):

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.

@dilyanpalauzov
Copy link
Author

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 rollup/plugins#393 .

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label May 14, 2020
@RyanCavanaugh
Copy link
Member

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.

@dilyanpalauzov
Copy link
Author

dilyanpalauzov commented May 14, 2020

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.

@dilyanpalauzov
Copy link
Author

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

@RyanCavanaugh
Copy link
Member

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

We don't rewrite import paths. See #35589

@dilyanpalauzov
Copy link
Author

dilyanpalauzov commented May 14, 2020

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).

@typescript-bot
Copy link
Collaborator

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.

@dilyanpalauzov
Copy link
Author

Well, this is not a question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants