Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement shim/polyfil for structuredClose() #558

Open
VenelinBakalov opened this issue Dec 6, 2024 · 2 comments
Open

Implement shim/polyfil for structuredClose() #558

VenelinBakalov opened this issue Dec 6, 2024 · 2 comments
Labels
area/ecmascript Relates to ecmascript module area/vrotsc Relates to `vrotsc` module effort/low kind/feature New Feature to the project lang/typescript Related to typescript code priority/low triage/needed Needs to be discussed by project maintainers version/minor Introduces a non-breaking feature or change

Comments

@VenelinBakalov
Copy link
Collaborator

VenelinBakalov commented Dec 6, 2024

Description

It is a common task that we need to deep clone an object and change it's values without affecting the original. It might be useful to implement a shim/polyfil for structuredClone() so that we have that function out of the box. This would lead to more consistency and simplicity across the different approaches of implementing similar solution (most of which actually do not deep clone the object and lead to issues and bugs later down the line).

  • the options.trasfer array implementation is nice to have but not a must

Alternatives

Additional Context

https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone

It can be something as simple as

        if (source === undefined || source === null) {
            throw new Error("Source value is mandatory.");
        }
        return JSON.parse(JSON.stringify(source));

Note that this has some restrictions, e.g. works mainly for simple objects

@VenelinBakalov VenelinBakalov added lang/typescript Related to typescript code area/vrotsc Relates to `vrotsc` module version/minor Introduces a non-breaking feature or change triage/needed Needs to be discussed by project maintainers kind/feature New Feature to the project area/ecmascript Relates to ecmascript module priority/low effort/low labels Dec 6, 2024
@Indy-rbo
Copy link
Contributor

Indy-rbo commented Dec 9, 2024

Recently ran into this and would love a polyfill for it! Preferably something close/similar to https://github.com/ungap/structured-clone

While I don't see much added value in the JSON implementation, I would like to request that in that case the function definition is overridden as well (if you have a method for doing that in the Build Tools).
Otherwise this implementation might confuse users when the behavior differs from the behavior of the identically named web API function.

Something like:

declare global {
  /**
   * Polyfill for {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone|`structuredClone`}
   * by calling `JSON.parse(JSON.stringify(value))`
   *
   * Warning: This polyfill works differently than `structuredClone`.
   *
   * It may not work as expected when dealing with complex types like:
   * 
   * - Dates
   * - functions
   * - undefined
   * - Infinity
   * - RegExps
   * - Maps
   * - Sets
   * - Blobs
   * - FileLists
   * - ImageDatas
   * - Sparse Arrays
   * - Typed Arrays
   * - Circular references
   */
  function structuredClone<T> (
    value: T,
    transfer?: { transfer: any[] },
  ): T
}

Which gives this hover info:
image

(might be a bit verbose but it's informative :))


As noted in the docblock:
The stringify approach doesn't work with:
Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays, circular references or other complex types within an object.

Some examples where the JSON approach works different:

{
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // removed from object
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost, becomes an empty object
  map: new Map().set('key', 'value'), // lost, becomes an empty object
}

image

@VenelinBakalov
Copy link
Collaborator Author

Nice, thanks for all the details, that would be useful! we will take look at the suggested polyfil, this is exactly the reason why we still haven't rushed into implementing this too quickly because the JSON implementation only covers very basic type. Which at the end is covering for most of the use cases but still is worth investigating alternatives

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/ecmascript Relates to ecmascript module area/vrotsc Relates to `vrotsc` module effort/low kind/feature New Feature to the project lang/typescript Related to typescript code priority/low triage/needed Needs to be discussed by project maintainers version/minor Introduces a non-breaking feature or change
Projects
None yet
Development

No branches or pull requests

2 participants