Repository: TypeScript
Issue: Define a global context in a function signature, to enforce typing.
Labels: Suggestion,Awaiting More Feedback

## 🔍 Search Terms

- global context
- enforce global variable


## ✅ 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 feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

I would like to be able to define that a method can have access to a custom global environment, within the function.
It can be implemented exactly as the *this* typing.
the main issue is to find a reserved keyword, or syntax to do that.

## 📃 Motivating Example

Improve puppeteer extensions.

## 💻 Use Cases

This feature is most useful when we write a code that will be executed in another javascript environment like:
- writing code that will be injected into a browser (like puppeteer)
- writing a code that will be called in a nodejs worker.

if I use [puppeteer-jquery](https://www.npmjs.com/package/puppeteer-jquery) to enable jQuery into my browser.

I can now write: 
```typescript
import puppeteer from 'puppeteer';
import { PageEx, pageExtend } from 'puppeteer-jquery'

interface Items{ item: string; } 

var jQuery: JQueryStatic; // declare that a jQuery object exists

const browser = puppeteer.launch(option); // start a browser
const page = await browser.newPage(); // create a tab
const page2 = pageExtend(page0); // inject jQuery to the page
const data = (await page.jQuery('div.entry').map((id: number, elm: HTMLElement) => {
    const impData = jQuery(elm).find('.important');
    return { item }
}).pojo()) as Items[];
```
the *jQuery* object is available inside the browser but not inside the nodeJS, this code works, but I need to add a dirty `var jQuery: JQueryStatic;` at the top of the file
currently, the jQuery map method of page signature is:
```
    map(mapping: (index: number, element: any) => any): PJQueryHybrid;
```
with a feature to define a custom environment, this code will be replaced by:

```typescript
import puppeteer from 'puppeteer';
import { PageEx, pageExtend } from 'puppeteer-jquery'

interface Items{ item: string; }

const browser = puppeteer.launch(option); // start a browser
const page = await browser.newPage(); // create a tab
const page2 = pageExtend(page0); // inject jQuery to the page
const data = (await page.jQuery('div.entry').map((id: number, elm: HTMLElement) => {
    const impData = jQuery(elm).find('.important');
    return { item }
}).pojo()) as Items[];
```
and, the jQuery method of page signature will be something like:
```typescript
interface JQPage{
    navigator: Navigator;
    jQuery: JQueryStatic;
    // ...
}
// this type is extracted from puppeteer-jquery, it's strange but it is correct.
type PJQueryHybrid = PJQuery & Promise<PJQuery>

interface Page {
    jQuery(global: JQPage, this: unknow, selector: string): PJQuery;
}

interface PJQuery {
    // current
    // map(callback: (this: TElement, index: number, element: TElement) => any): PJQueryHybrid;
    // new version 
    map(callback: (global: JQPage, this: TElement, index: number, element: TElement) => any): PJQueryHybrid;
}


```
### proposition:
The `this` parameter named is already reserved and must be placed in a first position.
if a `global` parameter is added before the `this` parameter it will be interpreted as a global environment, and so will not need reserving a new reserved keyword.


The tsConfig.json can be used to define if the code is used inside a nodeJS or a browser, but when we mixte the two destinations in the same code... it can not be used.