microsoft / microsoft/TypeScript
🚀 Proposal: Cross-Context Function Annotation (for APIs like `page.evaluate` of playwright)
还没有人认领这个 Issue。
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 2 天 4 小时
- 30 天内合并 PR
- 132
描述
### Acknowledgement
- [x] I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.
### Comment
## Motivation
APIs such as `page.evaluate` in browser automation libraries (e.g. Playwright) execute a function in a *different JavaScript runtime context* (browser context instead of Node.js).
Example:
```ts
const myText = "Hello world";
await page.evaluate(() => {
console.log(myText); // ❌ Runtime error (myText is not defined in browser)
});
```
Although this fails at runtime, TypeScript does **not** report an error. The compiler assumes the lambda executes in the same lexical and global environment as the caller.
This creates a mismatch between TypeScript’s static model and the actual runtime semantics of cross-context APIs.
---
## Problem Statement
TypeScript currently has no way to express that:
- A function executes in a **separate runtime context**
- The function must **not capture outer-scope variables**
- The function must **not access Node.js globals**
- The function runs against a specific global type (e.g. `Window`)
As a result:
- Accidental closure capture is allowed
- Incorrect global usage is not flagged
- Runtime errors occur that could be prevented at compile time
---
## Real-World Example
```ts
const secret = 42;
await page.evaluate(() => {
console.log(secret); // ❌ Runtime error: secret is not defined
});
```
TypeScript currently allows this because it has no notion of execution context isolation.
---
## Proposed Solution
Introduce a way to declare that a function:
1. Executes in a separate context
2. Has no access to outer lexical scope
3. Uses a specified global type
---
### Option A: `isolated` Function Modifier (New Syntax)
```ts
const myText = "Hello world";
await page.evaluate(isolated () => {
console.log(document.title); // ✅ OK
console.log(myText); // ❌ Compile error
});
```
**Semantics:**
- No closure capture allowed
- No outer-scope variable access
- Global type defined by API signature
- Treated as if compiled in a separate program with structured-clone semantics
This would be conceptually similar to `--isolatedModules`, but at function scope.
---
### Option B: `CrossContext` Type-Level Mechanism
If new syntax is not desirable, introduce a type-level mechanism:
```ts
type CrossContext =
(this: TGlobal, ...args: TArgs) => TResult;
```
Library usage example:
```ts
interface Page {
evaluate(
fn: CrossContext,
arg: A
): Promise;
}
```
With compiler rule:
- Functions of type `CrossContext<...>` may not reference outer lexical bindings
- Only globals available on `TGlobal` are allowed
Example behavior:
```ts
const x = 5;
await page.evaluate(() => {
console.log(x); // ❌ Error: outer scope capture not allowed
console.log(process); // ❌ Error: not part of Window
console.log(document); // ✅ OK
});
```
---
### Option C: JSDoc Annotation
```ts
await page.evaluate(
/** @crossContext Window */
() => {
console.log(document.title);
}
);
```
**Compiler behavior:**
- Treat function as isolated
- Restrict global access
- Disallow closure capture
This avoids syntax changes while still enabling static safety.
---
## Prior Art
- Web Workers (structured cloning, no shared closures)
- `postMessage` semantics
- Rust’s `Send` / `Sync` closure restrictions
- Sandboxed runtimes (e.g. Electron multi-process model)
---
## Benefits
- Prevents a common class of runtime errors
- Improves safety of browser automation, workers, and SSR
- Makes execution semantics explicit
- Improves editor tooling and developer experience
- Enables safer multi-runtime APIs
---
## Non-Goals
- Not intended as a security boundary
- Not intended to restrict normal functions
- Not a replacement for ESLint, but a stronger compiler guarantee
---
## Why This Belongs in TypeScript (Not Just ESLint)
While ESLint could detect some closure capture cases, only the TypeScript compiler can:
- Properly reason about type environments
- Enforce global type restrictions
- Integrate deeply with existing type inference
Cross-context execution is increasingly common in:
- Browser automation
- Workers
- Hybrid runtimes
- SSR frameworks
TypeScript currently has no way to model this distinction.
---
## Summary
TypeScript lacks a mechanism to model execution-context isolation. Introducing an `isolated` function modifier or a `CrossContext` constraint would prevent runtime errors and better reflect modern JavaScript runtime architectures.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
该 issue 没有指出源文件、测试或编译器入口点。首先,将提议的语法、type-level 和 JSDoc 方案与闭包捕获和全局访问示例进行比较,然后定义编译器行为以及证明不同上下文之间隔离性所需的测试。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- javascript, typescript
- 领域
- compilers
- Issue 类型
- 功能
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 停滞
- 描述清晰度
- 需要澄清
- 新手友好度
- 25/100