Skip to content

Instantly share code, notes, and snippets.

@rbuckton
Last active March 19, 2021 22:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbuckton/02e3e9f13e4405184a1e4cfe2da69634 to your computer and use it in GitHub Desktop.
Save rbuckton/02e3e9f13e4405184a1e4cfe2da69634 to your computer and use it in GitHub Desktop.

__classPrivateFieldSet

var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "method") throw new TypeError("Private method is not writable");
    if (kind === "accessor" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "accessor" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};

Parameters:

  • receiver — The object on which the private member will be set (existing).
  • state — One of the following (existing):
    • A WeakMap used to store a private instance field (existing).
    • A WeakSet used as an instance brand for private instance methods and accessors.
    • A function value that should be the undecorated class constructor used to brand check private static fields, methods, and accessors.
  • value — The value to set (existing case).
  • kind — (optional pre TS 4.3, required for TS 4.3+) One of the following values:
    • undefined — Indicates a private instance field (pre TS 4.3).
    • "field" — Indicates a private field (instance or static).
    • "method" — Indicates a private method (instance or static).
    • "accessor" — Indicates a private accessor (instance or static).
  • f — (optional pre TS 4.3) Depends on the arguments for state and kind:
    • If kind is "method", this should be the function corresponding to the static or instance method.
    • If kind is "accessor", this should be the function corresponding to the setter method, or undefined if the setter was not defined.
    • If kind is "field" and state is a function, this should be an object holding the value of a static field, or undefined if the static field declaration has not yet been evaluated.

Usage:

This helper will only ever be used by the compiler in the following ways:

  • Writing to a private instance field (pre TS 4.3):
    __classPrivateFieldSet(<any>, <WeakMap>, <any>)

  • Writing to a private instance field (TS 4.3+):
    __classPrivateFieldSet(<any>, <WeakMap>, <any>, "field")

  • Writing to a private instance set accessor (when defined, TS 4.3+):
    __classPrivateFieldSet(<any>, <WeakSet>, <any>, "accessor", <function>)

  • Writing to a private instance set accessor (when not defined, TS 4.3+):
    __classPrivateFieldSet(<any>, <WeakSet>, <any>, "accessor", void 0)

    • NOTE: This always results in a runtime error.
  • Writing to a private instance method (TS 4.3+):
    __classPrivateFieldSet(<any>, <WeakSet>, <any>, "method", <function>)

    • NOTE: This always results in a runtime error.
  • Writing to a private static field (TS 4.3+):
    __classPrivateFieldSet(<any>, <constructor>, <any>, "field", <{ value: any }>)

  • Writing to a private static set accessor (when defined, TS 4.3+):
    __classPrivateFieldSet(<any>, <constructor>, <any>, "accessor", <function>)

  • Writing to a private static set accessor (when not defined, TS 4.3+):
    __classPrivateFieldSet(<any>, <constructor>, <any>, "accessor", void 0)

    • NOTE: This always results in a runtime error.
  • Writing to a private static method (TS 4.3+):
    __classPrivateFieldSet(<any>, <constructor>, <any>, "method", <function>)

    • NOTE: This always results in a runtime error.

Algorithm:

  1. if (kind === "method") throw new TypeError("Private method is not writable");

    NOTE: This matches the order for Private State-related Errors Thrown by V8.

    Private methods (instance or static) are not writable.

  2. if (kind === "accessor" && !f) throw new TypeError("Private accessor was defined without a setter");

    NOTE: This matches the order for Private State-related Errors Thrown by V8.

    A private accessor (instance or static) without a setter throws when an attempt is made to set a value.

  3. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");

    We will break this down into each branch:

    1. If typeof state === "function", then:
      1. NOTE: This invocation is for a static member, as state will be the constructor function.
      2. If receiver !== state, then
        1. NOTE: The receiver is not the class and thus fails the brand check.
        2. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        3. Throw a TypeError.
      3. If !f, then
        1. NOTE: kind cannot be undefined here, as undefined is only provided when pre TS 4.3 emit encounters this updated helper, which never supported static members. TS 4.3+ will always emit the kind.
        2. NOTE: kind cannot be "method" here as that was removed as a constituent in Step 1.
        3. NOTE: kind cannot be "accessor" here, as an "accessor" with a missing f was tested in Step 2.
        4. NOTE: kind can only be "field" here, given the above. A "field" with a missing storage object has not yet had its declaration evaluated.
        5. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        6. Throw a TypeError.
    2. Else,
      1. NOTE: This invocation is for an instance member, as state will be either a WeakMap (for private fields), or a WeakSet (for private methods or accessors).
      2. NOTE: Both WeakMap and WeakSet have a has method that can be used to test for presence.
      3. If !state.has(receiver), then
        1. NOTE: The receiver failed the brand check.
        2. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        3. Throw a TypeError.
  4. return (kind === "accessor" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;

    We will break this down into each branch:

    1. NOTE: The comma expression here will expression on the left of the ,, but result in the value on the right.
    2. NOTE: kind cannot be "method" here, as that was tested in Step 1.
    3. If kind === "accessor", then
      1. NOTE: f will be defined here, as an "accessor" with a missing f was tested in Step 2.
      2. Evaluate the setter using f.call(receiver, value).
    4. Else, if f is truthy, then
      1. NOTE: Per Step 1, we know that kind cannot be "method", so f cannot be a method function.
      2. NOTE: Per Step 4.i, we know that kind cannot be "accessor", so f cannot be an accessor function.
      3. NOTE: f is not provided for instance fields before or after TS 4.3, so its presence can only indicate a static private field.
      4. NOTE: A static private field with a missing f was tested in Step 3.i.c, therefore f must be the static private field descriptor.
      5. Set f.value = value.
    5. Else,
      1. NOTE: kind must either be "field" (in TS 4.3+), or undefined (pre TS 4.3). Either way, this must be an instance field per Step 4.iii
      2. NOTE: As this is an instance field, state will be a WeakMap as the compiler will only provide a function for static members and a WeakSet for methods or accessors.
      3. Store the field value using state.set(receiver, value)
    6. Return value.

__classPrivateFieldGet

var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "accessor" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "method" ? f : kind === "accessor" ? f.call(receiver) : f ? f.value : state.get(receiver);
};

Parameters:

  • receiver — The object from which the private member will be read (existing).
  • state — One of the following (existing):
    • A WeakMap used to read a private instance field (existing).
    • A WeakSet used as an instance brand for private instance methods and accessors.
    • A function value that should be the undecorated class constructor used to brand check private static fields, methods, and accessors.
  • kind — (optional pre TS 4.3, required for TS 4.3+) One of the following values:
    • undefined — Indicates a private instance field (pre TS 4.3).
    • "field" — Indicates a private field (instance or static).
    • "method" — Indicates a private method (instance or static).
    • "accessor" — Indicates a private accessor (instance or static).
  • f — (optional pre TS 4.3) Depends on the arguments for state and kind:
    • If kind is "method", this should be the function corresponding to the static or instance method.
    • If kind is "accessor", this should be the function corresponding to the getter method, or undefined if the getter was not defined.
    • If kind is "field" and state is a function, this should be an object holding the value of a static field, or undefined if the static field declaration has not yet been evaluated.

Usage:

This helper will only ever be used by the compiler in the following ways:

  • Reading from a private instance field (pre TS 4.3):
    __classPrivateFieldGet(<any>, <WeakMap>)

  • Reading from a private instance field (TS 4.3+):
    __classPrivateFieldGet(<any>, <WeakMap>, "field")

  • Reading from a private instance get accessor (when defined, TS 4.3+):
    __classPrivateFieldGet(<any>, <WeakSet>, "accessor", <function>)

  • Reading from a private instance get accessor (when not defined, TS 4.3+):
    __classPrivateFieldGet(<any>, <WeakSet>, "accessor", void 0)

    • NOTE: This always results in a runtime error.
  • Reading from a private instance method (TS 4.3+):
    __classPrivateFieldGet(<any>, <WeakSet>, "method", <function>)

  • Reading from a private static field (TS 4.3+):
    __classPrivateFieldGet(<any>, <constructor>, "field", <{ value: any }>)

  • Reading from a private static get accessor (when defined, TS 4.3+):
    __classPrivateFieldGet(<any>, <constructor>, "accessor", <function>)

  • Reading from a private static get accessor (when not defined, TS 4.3+):
    __classPrivateFieldGet(<any>, <constructor>, "accessor", void 0)

    • NOTE: This always results in a runtime error.
  • Reading from a private static method (TS 4.3+):
    __classPrivateFieldGet(<any>, <constructor>, "method", <function>)

Algorithm:

  1. if (kind === "accessor" && !f) throw new TypeError("Private accessor was defined without a getter");

    A private accessor (instance or static) without a getter throws when an attempt is made to read from the accessor.

    NOTE: This matches the order for Private State-related Errors Thrown by V8.

  2. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");

    We will break this down into each branch:

    1. If typeof state === "function", then:
      1. NOTE: This invocation is for a static member, as state will be the constructor function.
      2. If receiver !== state, then
        1. NOTE: The receiver is not the class, and thus fails the brand check.
        2. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        3. Throw a TypeError.
      3. If !f, then
        1. NOTE: kind cannot be undefined here, as undefined is only provided when pre TS 4.3 emit encounters this updated helper, which never supported static members. TS 4.3+ will always emit the kind.
        2. NOTE: kind cannot be "accessor" here, as an "accessor" with a missing f was tested in Step 1.
        3. NOTE: When kind is "method", f will always be provided.
        4. NOTE: kind can only be "field" here, given the above. A "field" with a missing storage object has not yet had its declaration evaluated.
        5. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        6. Throw a TypeError.
    2. Else,
      1. NOTE: This invocation is for an instance member, as state will be either a WeakMap (for private fields), or a WeakSet (for private methods or accessors).
      2. NOTE: Both WeakMap and WeakSet have a has method that can be used to test for presence.
      3. If !state.has(receiver), then
        1. NOTE: This means the receiver failed the brand check.
        2. NOTE: This matches the order for Private State-related Errors Thrown by V8.
        3. Throw a TypeError.
  3. return kind === "method" ? f : kind === "accessor" ? f.call(receiver) : f ? f.value : state.get(receiver);

    We will break this down into each branch:

    1. If kind === "method", then
      1. NOTE: f will always be provided when kind is "method".
      2. Return f.
    2. If kind === "accessor", then
      1. NOTE: f will be defined here, as an "accessor" with a missing f was tested in Step 2.
      2. Return f.call(receiver).
    3. Else, if f is truthy, then
      1. NOTE: Per Step 3.i, we know that kind cannot be "method", so f cannot be a method function.
      2. NOTE: Per Step 3.ii, we know that kind cannot be "accessor", so f cannot be an accessor function.
      3. NOTE: f is not provided for instance fields before or after TS 4.3, so its presence can only indicate a static private field.
      4. NOTE: A static private field with a missing f was tested in Step 2.i.c, therefore f must be the static private field descriptor.
      5. Return f.value.
    4. Else,
      1. NOTE: kind must either be "field" (in TS 4.3+), or undefined (pre TS 4.3). Either way, this must be an instance field per Steps 3.i through 3.iii.
      2. NOTE: As this is an instance field, state will be a WeakMap as the compiler will only provide a function for static members and a WeakSet for methods or accessors.
      3. Return state.get(receiver).

Private State-related Errors Thrown by V8

V8 thows a TypeError with one of the following messages in various cases of private state access:

NOTE: Each case below is in the order that it would be tested. For example, a violation of case (1) will throw before a violation of case (4).

  1. Private method '<name>' is not writable - when attempting to write to a private method (static or instance)
  2. '<name>' was defined without a setter - when attempting to set a private accessor that has no setter (static or instance)
  3. '<name>' was defined without a getter - when attempting to read a private accessor that has no getter (static or instance)
  4. Object must be an instance of class <name> - when calling a private method on the wrong instance
  5. Cannot read private member <name> from an object whose class did not declare it - when reading a private field or accessor from the wrong instance, or when reading a private static field whose declaration has not yet been evaluated. Also used when calling a private static method on the wrong object.
  6. Cannot write private member <name> to an object whose class did not declare it - when writing a private field or accessor to the wrong instance, or when writing a private static field whose declaration has not yet been evaluated.

I believe (4) is sufficiently covered by (5), and is therefore unnecessary. This is motivated by the fact that (5) is used as the error message for the static method case.

@ExE-Boss
Copy link

void 0 in trailing parameters can be omitted, since they default to undefined.

@rbuckton
Copy link
Author

Up until recently, v8's optimizations for calling a function with a different arity (fewer or more arguments than there are specified parameters), was subpar. It essentially compiled a separate function with the supplied arity that forwarded to the actual function. Fully supplying arguments (even with undefined) resulted in better performance.

@rbuckton
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment