microsoft / microsoft/TypeScript

Alternative to rewriteRelativeImportExtensions & allowImportingTsExtensions

Đang mở
#61,050 2 bình luận 2 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Awaiting More Feedback Suggestion
Ngôn ngữ chính
Go
Star
111k
Fork
14.3k
Merge trung bình
2 ngày 4 giờ
Pull request đã merge (30 ngày)
132

Mô tả

### 🔍 Search Terms

"rewriteRelativeImportExtensions", "allowImportingTsExtensions", "extension', "rewrite", "tsc"

### ✅ Viability Checklist

- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

Although the recent `rewriteRelativeImportExtensions` tsc option is a big step forward with the more and more needed feature of rewriting `.ts` extensions to `.js` when compiling with tsc, it suffers of some drawbacks (may emit shims, false-positives, developer de-responsabilisation, ...) and limitations imposed by the very reasonable [Typescript design goals](https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals) or other things well described by Ryan Cavanaugh in https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1435399267.
The older option `allowImportingTsExtensions` is, for its part, a workaround to permit run-in-place usages (directly executing TS sources, with no compilation, as if it was a JS file), that didn't exist at the TS creation time.

Today, I want to propose a solution way more generic I never seen before in any conversations around these features/needs. What is complex and incertain for the compiler here? Something very trivial for a human: determining which string literals (please note: "string literals") in the TS source code are paths pointing to TS files that, once built, will point to JS files. Really transforming such strings is not a big deal, but determining which ones is, because it may depends on a huge amount of configurations, alias, module resolver and other wild things. So, if it's so simple for a human, why not asking him/her to bring this knowledge to the compiler?

So, here is the `// @ts-rewrite-ts-extension` comment (the name doesn't matter at this point, and my English is definitely improvable). The main and unique goal of it, is indicating to tsc that it should transform the nearby literal string ending with `.ts` to `.js` before doing any treatments on this string (also for other members of this family: `.tsx`, `.mts`, or `.cts` to their "j" counterpart). Why I keep talking about string literals and not about paths? Because it absolutely doesn't matter and will permit the developer to handle its own cases, even dynamic imports, explicitly and with no runtime shim.
An indirect consequence is, if this transformation occurs before the `allowImportingTsExtensions: false` check (TS5097) in the tsc process, this option doesn't need to be turned on anymore to allow importing `.ts` extensions, as they will be seen as `.js` (and valid) by this check. It's totally in the spirit of the TS5097 error to forbid clearly invalid paths and to allow those possibly valid once built.

This idea is now yours, improve and refine it or maybe even throw it away. 🙂

### 📃 Motivating Example

ESM `import` (or `export from`):
```ts
// two lines form
// @ts-rewrite-ts-extension
import * from './foo.ts';

// single line
import * from './foo.ts'; // @ts-rewrite-ts-extension
```

CJS `require`:
```ts
const lib = require('./foo.ts'); // @ts-rewrite-ts-extension
```

ESM functional `import()`:
```ts
const dynamic = await import('./foo.ts'); // @ts-rewrite-ts-extension

// with a simple string
const filepath = './foo.ts'; // @ts-rewrite-ts-extension
...
const dynamic = await import(filepath);

// with a constructed string
let filepath = BASE_PATH;
...
filepath += 'foo.ts'; // @ts-rewrite-ts-extension
...
const dynamic = await import(filepath);
```

Why not a block form in which all string literals will be transformed?
```ts
// @ts-rewrite-ts-extension-begin
import * from './foo1.ts';
import * from './foo2.ts';
import * from './foo3.ts';
// @ts-rewrite-ts-extension-end
```

No matter the reason why the developer wants to rewrite the extension, any eligible literal can be transformed:
```ts
// module specifier
import * from '#blah/foo.ts'; // @ts-rewrite-ts-extension

// really anything
console.log('./foo.ts'); // @ts-rewrite-ts-extension
```

### 💻 Use Cases

1. What do you want to use this for?
Creating TS projects that can run-in-place in Node, but also buildable with tsc and distributed as npm packets, with a unique code base.

2. What shortcomings exist with current approaches?
See the suggestion block

3. What workarounds are you using in the meantime?
tsx because it doesn't impose the Node Typescript restriction on extensions, and more recently tried `rewriteRelativeImportExtensions`.

4. Other improvements around this proposition:
- When used on non-eligible string literals, i.e. a string not ending by a `.ts` extension, an error may be emitted by tsc, because it's a clear mistake. Bad usage example:
```ts
// Error TSXXXX: Why the hell you want to transform an inexistant .ts extension?
import * from './foo.js'; // @ts-rewrite-ts-extension
```
- When used on lines with multiple string literals, an error may also be thrown to avoid any ambiguities.
```ts
// Error TSXXXX: Ambiguous @ts-rewrite-ts-extension usage, multiple strings can be affected
console.log('bar', './foo.ts'); // @ts-rewrite-ts-extension
```

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Đề xuất này liên quan đến cách tsc xử lý rewriteRelativeImportExtensions, allowImportingTsExtensions, string literal và các chỉ thị chú thích. Trước tiên, hãy xem xét các đường dẫn của compiler cho những tùy chọn này và TS5097, sau đó xác định chỉ thị được yêu cầu sẽ tương tác như thế nào với imports, require, dynamic import và các chuỗi thông thường. Công việc được xem là hoàn tất khi có một thiết kế đã được thống nhất và coverage cho các dạng extension và directive được liệt kê.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
typescript
Lĩnh vực
compilers
Loại issue
Tính năng
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Cần làm rõ
Mức phù hợp với người mới
25/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.