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

Add self.structuredClone() #11539

Closed
lucacasonato opened this issue Jul 27, 2021 · 1 comment · Fixed by #11572
Closed

Add self.structuredClone() #11539

lucacasonato opened this issue Jul 27, 2021 · 1 comment · Fixed by #11572
Labels
ext/web related to the ext/web crate feat new feature (which has been agreed to/accepted) web related to Web APIs
Milestone

Comments

@lucacasonato
Copy link
Member

Spec: whatwg/html@1b5099f

@lucacasonato lucacasonato added web related to Web APIs feat new feature (which has been agreed to/accepted) ext/web related to the ext/web crate labels Jul 27, 2021
@lucacasonato lucacasonato added this to the 1.13.0 milestone Jul 27, 2021
@bartlomieju bartlomieju modified the milestones: 1.13.0, 1.14.0 Aug 6, 2021
@jeremyBanks
Copy link
Contributor

jeremyBanks commented Aug 7, 2021

Should we consider giving this a somewhat-precise type signature, instead of returning any?

I'm not sure whether this would be appropriate or not, but here's a take on a function signature that preserves most type information for supported types, while stripping out methods for custom types.

It might not be perfect, but we should be able to get something close enough that the type information comes in handy much more often than it gets in the way (by forcing a cast).

export const clone = <Value>(value: Value) =>
  deserialize(serialize(value)) as Cloned<Value>;

const serialize = (value: unknown) =>
  // deno-lint-ignore no-explicit-any
  (Deno as any).core.serialize(value) as Uint8Array;

const deserialize = (bytes: Uint8Array) =>
  // deno-lint-ignore no-explicit-any
  (Deno as any).core.deserialize(bytes) as unknown;

// deno-fmt-ignore
type Cloned<Value>
  // preserve supported value types as-is
  = Value extends CloneablePrimitives | CloneableValues
    ? Value
  : RW<Value> extends CloneablePrimitives | CloneableValues
    ? Value
  // deno-lint-ignore ban-types
  : Value extends Function
    ? never
  // recur over parameters of supported collection types
  : RW<Value> extends Map<infer K, infer V>
    ? Map<Cloned<K>, Cloned<V>>
  : RW<Value> extends Set<infer V>
    ? Set<Cloned<V>>
  : RW<Value> extends Array<unknown> | Record<string, unknown>
    ? { [Key in keyof Value]: Cloned<Value[Key]> }
  : never;

type Cloneable =
  | CloneablePrimitives
  | CloneableCollections
  | CloneableValues;

type CloneablePrimitives =
  | bigint
  | boolean
  | null
  | number
  | string
  | undefined;

type CloneableCollections =
  | Set<Cloneable>
  | Map<Cloneable, Cloneable>
  | Array<Cloneable>
  | { [key: string]: Cloneable };

type CloneableValues =
  | ArrayBuffer
  | ArrayBufferView
  | BigInt
  | Blob
  // deno-lint-ignore ban-types
  | Boolean
  | Date
  | Error
  | EvalError
  // deno-lint-ignore ban-types
  | Number
  | RangeError
  | ReferenceError
  | RegExp
  // deno-lint-ignore ban-types
  | String
  | SyntaxError
  | TypeError
  | URIError;

/**
 * Removes readonly modifiers within a type (making it [r]ead[w]rite).
 *
 * We use this to help match against types while ignoring readonly modifiers.
 */
type RW<T> = {
  -readonly [P in keyof T]: RW<T[P]>;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ext/web related to the ext/web crate feat new feature (which has been agreed to/accepted) web related to Web APIs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants