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');