Last active
July 22, 2025 20:37
-
-
Save petsel/fcba946d3f4bff470c4f1b6b4f3103f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Module: function.bind.with-exotic-object-slots | |
| * | |
| * TypeScript declaration for a custom override of `Function.prototype.bind` | |
| * that stores ECMAScript-like internal slot metadata as Symbol-based properties | |
| * on bound functions. | |
| * | |
| * Inspired by ECMAScript internal slots: | |
| * - `[[BoundTargetFunction]]` | |
| * - `[[BoundThis]]` | |
| * - `[[BoundArguments]]` | |
| * | |
| * Specification References: | |
| * - https://tc39.es/ecma262/#bound-function-exotic-object | |
| * - https://tc39.es/ecma262/#sec-function.prototype.bind | |
| */ | |
| declare module 'function.bind.with-exotic-object-slots' { | |
| /** | |
| * Public symbols used to access internal metadata on bound functions. | |
| * These mimic ECMAScript internal slot names (wrapped in `[[ ]]`). | |
| */ | |
| /** | |
| * Symbolic key representing `[[TargetFunction]]` (equal to the Chrome-Dev-Tool specific implementation). | |
| * Equivalent to ECMAScript's internal `[[BoundTargetFunction]]` slot. | |
| * | |
| * Use to access a bound function's original source/function: | |
| * `boundFn[boundFunctionKey]` | |
| */ | |
| export const boundFunctionKey: unique symbol; | |
| /** | |
| * Symbolic key representing `[[BoundThis]]`. | |
| * Does equal ECMAScript's internal `[[BoundThis]]` slot. | |
| * | |
| * Use to access a bound function's `thisArg`: | |
| * `boundFn[boundThisArgKey]` | |
| */ | |
| export const boundThisArgKey: unique symbol; | |
| /** | |
| * Symbolic key representing `[[BoundArgs]]` (equal to the Chrome-Dev-Tool specific implementation). | |
| * Equivalent to ECMAScript's internal `[[BoundArguments]]` slot. | |
| * | |
| * Use to access a bound function's partially applied arguments: | |
| * `boundFn[boundArgsKey]` | |
| */ | |
| export const boundArgsKey: unique symbol; | |
| /** | |
| * Applies the custom `bind` override to `Function.prototype.bind` | |
| * and injects metadata-augmented binding behavior. | |
| */ | |
| export function applyPrototypeChange(): void; | |
| /** | |
| * Restores the native `Function.prototype.bind` behavior. | |
| */ | |
| export function restorePrototypeDefault(): void; | |
| /** | |
| * Generic utility `bind` method. | |
| * | |
| * An alternative static variant to the custom `bind` override | |
| * of the `Function.prototype.bind` method which creates bound | |
| * functions with metadata. | |
| * | |
| * @template {(...args: any[]) => any} T | |
| * @param {T} targetFct - The function to bind. | |
| * @param {any} thisArg - The `this` value to bind. | |
| * @param {...Parameters<T>} args - The arguments to pre-bind. | |
| * @returns {T} A new bound function, decorated with symbol-keyed metadata. | |
| */ | |
| export function bind<T extends (...args: any[]) => any>( | |
| targetFct: T, | |
| thisArg: any, | |
| ...args: Parameters<T> | |
| ): T; | |
| } | |
| /** | |
| * Global augmentation of the `Function` prototype to | |
| * reflect the symbol-keyed metadata installed by the | |
| * custom `bind` override. | |
| * These properties exist only on functions returned | |
| * by the prototypal custom `bind` method. | |
| */ | |
| interface Function { | |
| /** | |
| * A reference to the original (unbound) target function. | |
| * Equivalent to ECMAScript's internal `[[BoundTargetFunction]]` slot. | |
| */ | |
| [Symbol.for('[[TargetFunction]]')]?: Function; | |
| /** | |
| * A reference to the `thisArg` value bound during `bind(...)`. | |
| * Does equal ECMAScript's internal `[[BoundThis]]` slot. | |
| */ | |
| [Symbol.for('[[BoundThis]]')]?: unknown; | |
| /** | |
| * A reference to the partially applied arguments bound during `bind(...)`. | |
| * Equivalent to ECMAScript's internal `[[BoundArguments]]` slot. | |
| */ | |
| [Symbol.for('[[BoundArgs]]')]?: unknown[]; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // see ... [https://tc39.es/ecma262/#bound-function-exotic-object] | |
| // see ... [https://tc39.es/ecma262/#sec-function.prototype.bind] | |
| const functionPrototype = Function.prototype; | |
| const builtInBind = functionPrototype.bind; | |
| /** @type {PropertyDescriptor} */ | |
| const bindFunctionDescriptor = | |
| Object.getOwnPropertyDescriptor(functionPrototype, 'bind'); | |
| /** @type {PropertyDescriptor} */ | |
| const bindFunctionNameDescriptor = | |
| Object.getOwnPropertyDescriptor(builtInBind, 'name'); | |
| /** @type {PropertyDescriptor} */ | |
| const slotDescriptorOptions = { | |
| enumerable: false, | |
| writable: false, | |
| configurable: false, | |
| }; | |
| /** | |
| * Symbolic key representing `[[TargetFunction]]` (equal to the Chrome-Dev-Tool specific implementation). | |
| * A reference to the original (unbound) target function. | |
| * Equivalent to ECMAScript's internal `[[BoundTargetFunction]]` slot. | |
| * | |
| * Use to access a bound function's original source/function: | |
| * `boundFn[boundFunctionKey]` | |
| * | |
| * @constant | |
| * @type {unique symbol} | |
| */ | |
| export const boundFunctionKey = Symbol.for('[[TargetFunction]]'); // Symbol.for('[[BoundTargetFunction]]') | |
| /** | |
| * Symbolic key representing `[[BoundThis]]`. | |
| * A reference to the `thisArg` value bound during `bind(...)`. | |
| * Does equal ECMAScript's internal `[[BoundThis]]` slot. | |
| * | |
| * Use to access a bound function's `thisArg`: | |
| * `boundFn[boundThisArgKey]` | |
| * | |
| * @constant | |
| * @type {unique symbol} | |
| */ | |
| export const boundThisArgKey = Symbol.for('[[BoundThis]]'); // Symbol.for('[[BoundThis]]'); | |
| /** | |
| * Symbolic key representing `[[BoundArgs]]` (equal to the Chrome-Dev-Tool specific implementation). | |
| * A reference to the partially applied arguments bound during `bind(...)`. | |
| * Equivalent to ECMAScript's internal `[[BoundArguments]]` slot. | |
| * | |
| * Use to access a bound function's partially applied arguments: | |
| * `boundFn[boundArgsKey]` | |
| * | |
| * @constant | |
| * @type {unique symbol} | |
| */ | |
| export const boundArgsKey = Symbol.for('[[BoundArgs]]'); // Symbol.for('[[BoundArguments]]'); | |
| /** | |
| * Creates a bound function with slot-like metadata. | |
| * | |
| * @this {Function} | |
| * @param {*} thisArg - The value to bind as `this`. | |
| * @param {...*} args - Arguments to bind. | |
| * @returns {Function} A new bound function with internal metadata. | |
| */ | |
| function bind(thisArg, ...args) { | |
| 'hide source'; | |
| const targetFct = /** @type {Function} */ (this); | |
| const bound = builtInBind.call(targetFct, thisArg, ...args); | |
| Object.defineProperty(bound, boundFunctionKey, { ...slotDescriptorOptions, value: targetFct }); | |
| Object.defineProperty(bound, boundThisArgKey, { ...slotDescriptorOptions, value: thisArg }); | |
| Object.defineProperty(bound, boundArgsKey, { ...slotDescriptorOptions, value: [...args] }); | |
| return bound; | |
| } | |
| const proceed = bind; | |
| Object.defineProperty(bind, 'name', { ...bindFunctionNameDescriptor, value: 'bind' }); | |
| /** | |
| * Generic utility `bind` method. | |
| * | |
| * An alternative static variant to the custom `bind` override | |
| * of the `Function.prototype.bind` method which creates bound | |
| * functions with metadata. | |
| * | |
| * @template {(...args: any[]) => any} T | |
| * @param {T} targetFct - The function to bind. | |
| * @param {*} thisArg - The `this` value to bind. | |
| * @param {...Parameters<T>} args - The arguments to pre-bind. | |
| * @returns {T} A new bound function, decorated with symbol-keyed metadata. | |
| */ | |
| export function bind(targetFct, thisArg, ...args) { | |
| 'hide source'; | |
| return /** @type {T} */ ( | |
| proceed.call(targetFct, thisArg, ...args) | |
| ); | |
| } | |
| /** | |
| * Applies the custom `bind` override to `Function.prototype.bind` | |
| * and injects metadata-augmented binding behavior. | |
| */ | |
| export function applyPrototypeChange() { | |
| Object.defineProperty(functionPrototype, 'bind', { | |
| ...bindFunctionDescriptor, | |
| value: bind, | |
| }); | |
| } | |
| /** | |
| * Restores the native `Function.prototype.bind` behavior. | |
| */ | |
| export function restorePrototypeDefault() { | |
| Object.defineProperty(functionPrototype, 'bind', { | |
| ...bindFunctionDescriptor, | |
| value: builtInBind, | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment