microsoft / microsoft/TypeScript
Scoped module declarations
まだ誰も着手していません。
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.3k
- 平均マージ
- 2日 4時間
- マージ済み PR(30日)
- 132
説明
🔍 Search Terms
scoped module declarations, scoped globals, scoping global types
✅ Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion
In todays web ecosystem that's getting more complex and feature-rich it's very hard to get the desired functionality by declaring normal modules. I will cover one primary example so you can understand the issue and how it would be solved, primarily through vitest global test context. Vitest offers you a way to use setup files to inject functions/other utilities into their context by using a beforeEach hook. The way you would type what you passed into it is like the following:
declare module "vitest" {
export interface TestContext {
foo: typeof foo
bar: typeof bar
}
}
this makes it globally available in all test suites. BUT, here's the problem. let's say you add integration tests as well, and you have another setup file that adds the following to the test context:
declare module "vitest" {
export interface TestContext {
integration: typeof integration
}
}
Well, this creates an issue where whenever you try to access these globally defined contexts you have no idea if they are actually defined in the context they are running in, because the normal test suite has foo and bar, and the integration test suite has integration defined in the context. If you try to use foo in integration tests TS wouldn't complain but this would fail.
My idea is the following
// Define a unique `scope` keyword that scopes the following module augmentation to specific files that match a glob pattern
declare module "vitest" scope "**/*.unit.test.*" {
export interface TestContext {
foo: typeof foo
bar: typeof bar
}
}
This would override the module ONLY in files that match the scope, namely, in this case .unit.test.* files and then if we tried to use the foo or bar functionalities inside of there it wouldn't work. So to fix the problem from above, one would simply do the following:
// This overrides the unit.test suite
declare module "vitest" scope "**/*.unit.test.*" {
export interface TestContext {
foo: typeof foo
bar: typeof bar
}
}
// This overrides the integration.test suite
declare module "vitest" scope "**/*.integration.test.*" {
export interface TestContext {
integration: typeof something
}
}
now in your integration tests you could do:
it("works", ({ integration }) => {
// this is defined
integration.something
})
and in your unit tests:
it("works", ({ renderDevTools, integration }) => {
// this is defined
renderDevTools
// this is NOT defined and Typescript would complain
integration
})
other useful usecases:
*.server.ts=> makewindowobject undefined*.client.ts=> makeprocessobject undefined- help framework authors / normal users declare globals in specific files where they are exposed
- help framework authors / normal users inject custom utilities into specific functions/files
📃 Motivating Example
- Allows you to create multiple overrides in specific contexts giving you actual typesafety instead of a potential footgun
- Allows framework authors to exclude/include specific utilities/globals in places where they should be included/omitted for you, without you needing to guard against it (like
windowandprocessobjects in SSR frameworks like Remix/React Router and Next.js) - Allows third party tooling to provide you with scoped globals without you having to configure anything manually
- and more...
💻 Use Cases
- To make
processobject undefined in client only files - To make
windowobject undefined in server only files - There are no workarounds for this, the only thing you could do is mark the object as
undefinedso you don't forget to add a?in front of it so it doesn't crash your application if used somewhere where it's not supposed to be used
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
この issue では、リポジトリのファイル、テスト、エントリポイントが特定されていません。まず、TypeScript が module augmentation とグローバルな型の利用可能性をどのように扱うかを確認し、次に scoped declarations がファイルパターンにどのように適用されるべきか、またスコープ外の globals がどのように型エラーを発生させるべきかを判断してください。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- typescript
- 領域
- compilers
- issue の種類
- 機能追加
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 30/100