microsoft / microsoft/TypeScript
🚀 Proposal: Cross-Context Function Annotation (for APIs like `page.evaluate` of playwright)
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Go
- Estrellas
- 111k
- Forks
- 14.3k
- Merge medio
- 2 d 4 h
- PR fusionados (30 d)
- 132
Descripción
Acknowledgement
- 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:
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
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:
- Executes in a separate context
- Has no access to outer lexical scope
- Uses a specified global type
Option A: isolated Function Modifier (New Syntax)
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<TGlobal> Type-Level Mechanism
If new syntax is not desirable, introduce a type-level mechanism:
type CrossContext<TGlobal, TArgs extends any[], TResult> =
(this: TGlobal, ...args: TArgs) => TResult;
Library usage example:
interface Page {
evaluate<R, A>(
fn: CrossContext<Window, [A], R>,
arg: A
): Promise<R>;
}
With compiler rule:
- Functions of type
CrossContext<...>may not reference outer lexical bindings - Only globals available on
TGlobalare allowed
Example behavior:
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
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)
postMessagesemantics- Rust’s
Send/Syncclosure 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<TGlobal> constraint would prevent runtime errors and better reflect modern JavaScript runtime architectures.
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
El issue no menciona archivos fuente, pruebas ni puntos de entrada del compilador. Empieza comparando los enfoques propuestos de sintaxis, type-level y JSDoc con los ejemplos de captura de cierres y acceso global; después, define el comportamiento del compilador y las pruebas necesarias para demostrar el aislamiento entre contextos.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- javascript, typescript
- Área
- compilers
- Tipo de issue
- Nueva funcionalidad
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Estancado
- Claridad
- Necesita aclaración
- Aptitud para principiantes
- 25/100