diff --git a/packages/react-native/src/private/webapis/structuredClone/__tests__/structuredClone-itest.js b/packages/react-native/src/private/webapis/structuredClone/__tests__/structuredClone-itest.js index 402e055048da..873aab652944 100644 --- a/packages/react-native/src/private/webapis/structuredClone/__tests__/structuredClone-itest.js +++ b/packages/react-native/src/private/webapis/structuredClone/__tests__/structuredClone-itest.js @@ -82,6 +82,18 @@ describe('structuredClone', () => { expect(booleanClone).not.toBe(booleanValue); expect(booleanClone).toBeInstanceOf(Boolean); expect(booleanClone.valueOf()).toBe(true); + + const bigintValue = Object(1n); + // $FlowExpectedError[incompatible-use] this intentionally shadows the method. + Object.defineProperty(bigintValue, 'valueOf', { + value() { + throw new Error('Unexpected coercion'); + }, + }); + const bigintClone = structuredClone(bigintValue); + expect(bigintClone).not.toBe(bigintValue); + expect(bigintClone).toBeInstanceOf(BigInt); + expect(bigintClone.valueOf()).toBe(1n); }); it('throws with symbols, functions, WeakMap, WeakSet, Promise', () => { diff --git a/packages/react-native/src/private/webapis/structuredClone/structuredClone.js b/packages/react-native/src/private/webapis/structuredClone/structuredClone.js index 89a7f90725be..2be442a118c1 100644 --- a/packages/react-native/src/private/webapis/structuredClone/structuredClone.js +++ b/packages/react-native/src/private/webapis/structuredClone/structuredClone.js @@ -27,6 +27,8 @@ const VALID_ERROR_NAMES = new Set([ const BASIC_CONSTRUCTORS = [Number, String, Boolean, Date]; const ObjectPrototype = Object.prototype; +// $FlowFixMe[method-unbinding] this is always called with an explicit receiver. +const bigintValueOf = BigInt.prototype.valueOf; // Technically the memory value should be a parameter in // `structuredCloneInternal` but as an optimization we can reuse the same map @@ -104,6 +106,13 @@ function structuredCloneInternal(value: T): T { } } + if (value instanceof BigInt) { + const result = Object(bigintValueOf.call(value)); + memory.set(value, result); + // $FlowExpectedError[incompatible-type] we know result is T + return result; + } + if (value instanceof Map) { const result = new Map(); memory.set(value, result);