From 3012f94e629375ae03da180e2152da59fd42d9bb Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Wed, 14 Oct 2026 13:57:13 -0700 Subject: [PATCH] Polyfill Array copying methods (#59091) Summary: Install guarded `Array.prototype.toSorted` and `Array.prototype.toReversed` polyfills during default React Native environment setup. Both methods return shallow copies and preserve native implementations when the runtime already provides them. Register the language polyfills alongside the existing Promise setup rather than coupling them to the generic global-variable setup. Changelog: [General][Added] - Polyfill `Array.prototype.toSorted` and `Array.prototype.toReversed` when the JavaScript runtime does not provide them Differential Revision: D125283374 --- .../polyfillArrayES2023Methods-itest.js | 48 +++++++++++++++++++ .../Core/polyfillArrayES2023Methods.js | 40 ++++++++++++++++ .../setUpDefaultReactNativeEnvironment.js | 1 + 3 files changed, 89 insertions(+) create mode 100644 packages/react-native/Libraries/Core/__tests__/polyfillArrayES2023Methods-itest.js create mode 100644 packages/react-native/Libraries/Core/polyfillArrayES2023Methods.js diff --git a/packages/react-native/Libraries/Core/__tests__/polyfillArrayES2023Methods-itest.js b/packages/react-native/Libraries/Core/__tests__/polyfillArrayES2023Methods-itest.js new file mode 100644 index 000000000000..7e2c5342e15a --- /dev/null +++ b/packages/react-native/Libraries/Core/__tests__/polyfillArrayES2023Methods-itest.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @fantom_hermes_variant * + */ + +'use strict'; + +const originalToSorted = Array.prototype.toSorted; +const originalToReversed = Array.prototype.toReversed; + +require('@react-native/fantom/src/setUpDefaultReactNativeEnvironment'); + +describe('Array ES2023 method polyfills', () => { + it('preserves native methods and fills missing methods', () => { + if (originalToSorted == null) { + expect(Array.prototype.toSorted).toBeDefined(); + } else { + expect(Array.prototype.toSorted).toBe(originalToSorted); + } + + if (originalToReversed == null) { + expect(Array.prototype.toReversed).toBeDefined(); + } else { + expect(Array.prototype.toReversed).toBe(originalToReversed); + } + }); + + it('provides non-mutating copying behavior', () => { + const input = [3, 1, 2]; + + expect(input.toSorted((a, b) => a - b)).toEqual([1, 2, 3]); + expect(input.toReversed()).toEqual([2, 1, 3]); + expect(input).toEqual([3, 1, 2]); + expect( + Object.getOwnPropertyDescriptor(Array.prototype, 'toSorted')?.enumerable, + ).toBe(false); + expect( + Object.getOwnPropertyDescriptor(Array.prototype, 'toReversed') + ?.enumerable, + ).toBe(false); + }); +}); diff --git a/packages/react-native/Libraries/Core/polyfillArrayES2023Methods.js b/packages/react-native/Libraries/Core/polyfillArrayES2023Methods.js new file mode 100644 index 000000000000..1cb5dcf9df4c --- /dev/null +++ b/packages/react-native/Libraries/Core/polyfillArrayES2023Methods.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @format + */ + +'use strict'; + +const arrayPrototype = Array.prototype; + +if (arrayPrototype.toSorted == null) { + Object.defineProperty(arrayPrototype, 'toSorted' as string, { + configurable: true, + value: function ( + this: Array, + compareFn?: (a: T, b: T) => number, + ): Array { + const copy = Array.from(this); + copy.sort(compareFn); + return copy; + }, + writable: true, + }); +} + +if (arrayPrototype.toReversed == null) { + Object.defineProperty(arrayPrototype, 'toReversed' as string, { + configurable: true, + value: function (this: Array): Array { + const copy = Array.from(this); + copy.reverse(); + return copy; + }, + writable: true, + }); +} diff --git a/packages/react-native/src/private/setup/setUpDefaultReactNativeEnvironment.js b/packages/react-native/src/private/setup/setUpDefaultReactNativeEnvironment.js index b05bd70cb88c..5cd169a5377f 100644 --- a/packages/react-native/src/private/setup/setUpDefaultReactNativeEnvironment.js +++ b/packages/react-native/src/private/setup/setUpDefaultReactNativeEnvironment.js @@ -23,6 +23,7 @@ export default function setUpDefaultReactNativeEnvironment( require('./setUpDOM').default(); require('./setUpPerformance').default(); require('../../../Libraries/Core/polyfillPromise'); + require('../../../Libraries/Core/polyfillArrayES2023Methods'); require('../../../Libraries/Core/setUpTimers'); if (__DEV__ && enableDeveloperTools) { require('../../../Libraries/Core/setUpReactDevTools');