Fix backwards-compat for ModuleConstants<::Builder> (#54919)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54919

Add a new `ResultT` to codegen and some C++ trickery so that `ModuleConstants<Type::Builder>` is equal to ModuleConstants<Type> and existing overrides of the module spec remain compatible.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D89373357

fbshipit-source-id: ac192e99e424a829668722722cf0c374172de48b
This commit is contained in:
Pieter De Baets
2025-12-17 11:21:29 -08:00
committed by meta-codesync[bot]
parent 4de9242e80
commit d25af38453
5 changed files with 128 additions and 1 deletions
@@ -275,6 +275,9 @@ namespace JS {
struct ConstantsEEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEEE;
struct Input {
RCTRequired<bool> D;
RCTRequired<double> E;
@@ -304,6 +307,9 @@ namespace JS {
struct ConstantsEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEE;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsEEE::Builder> E;
@@ -333,6 +339,9 @@ namespace JS {
struct ConstantsE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsE;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsEE::Builder> E;
@@ -362,6 +371,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsE::Builder> E;
@@ -420,6 +432,9 @@ namespace JS {
struct ConstantsEEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEEE;
struct Input {
std::optional<bool> D;
std::optional<double> E;
@@ -449,6 +464,9 @@ namespace JS {
struct ConstantsEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEE;
struct Input {
std::optional<bool> D;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsEEE::Builder> E;
@@ -478,6 +496,9 @@ namespace JS {
struct ConstantsE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsE;
struct Input {
std::optional<bool> D;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsEE::Builder> E;
@@ -507,6 +528,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> D;
id<NSObject> _Nullable A;
@@ -698,6 +722,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<bool> const1;
RCTRequired<double> const2;
@@ -768,6 +795,9 @@ namespace JS {
struct ConstantsIdElement {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsIdElement;
struct Input {
RCTRequired<double> prop;
};
@@ -795,6 +825,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<std::vector<bool>> const1;
RCTRequired<std::vector<double>> const2;
@@ -896,6 +929,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<std::optional<bool>> const1;
RCTRequired<std::optional<double>> const2;
@@ -996,6 +1032,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> const1;
std::optional<double> const2;
@@ -1096,6 +1135,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> const1;
std::optional<double> const2;
@@ -1787,6 +1829,9 @@ namespace JS {
struct ConstantsEEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEEE;
struct Input {
RCTRequired<bool> D;
RCTRequired<double> E;
@@ -1816,6 +1861,9 @@ namespace JS {
struct ConstantsEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEE;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsEEE::Builder> E;
@@ -1845,6 +1893,9 @@ namespace JS {
struct ConstantsE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsE;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsEE::Builder> E;
@@ -1874,6 +1925,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<bool> D;
RCTRequired<JS::NativeObjectTurboModule::ConstantsE::Builder> E;
@@ -1932,6 +1986,9 @@ namespace JS {
struct ConstantsEEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEEE;
struct Input {
std::optional<bool> D;
std::optional<double> E;
@@ -1961,6 +2018,9 @@ namespace JS {
struct ConstantsEE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsEE;
struct Input {
std::optional<bool> D;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsEEE::Builder> E;
@@ -1990,6 +2050,9 @@ namespace JS {
struct ConstantsE {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsE;
struct Input {
std::optional<bool> D;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsEE::Builder> E;
@@ -2019,6 +2082,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> D;
id<NSObject> _Nullable A;
@@ -2210,6 +2276,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<bool> const1;
RCTRequired<double> const2;
@@ -2280,6 +2349,9 @@ namespace JS {
struct ConstantsIdElement {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ConstantsIdElement;
struct Input {
RCTRequired<double> prop;
};
@@ -2307,6 +2379,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<std::vector<bool>> const1;
RCTRequired<std::vector<double>> const2;
@@ -2408,6 +2483,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<std::optional<bool>> const1;
RCTRequired<std::optional<double>> const2;
@@ -2508,6 +2586,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> const1;
std::optional<double> const2;
@@ -2608,6 +2689,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
std::optional<bool> const1;
std::optional<double> const2;
@@ -35,6 +35,9 @@ const StructTemplate = ({
struct ${structName} {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = ${structName};
struct Input {
${builderInputProps}
};
@@ -1008,6 +1008,9 @@ namespace JS {
struct Constants {
struct Builder {
// Backwards compat for RCTTypedModuleConstants
using ResultT = Constants;
struct Input {
RCTRequired<bool> const1;
RCTRequired<double> const2;
@@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
#include <type_traits>
#include <utility>
#import <Foundation/Foundation.h>
@@ -32,10 +33,44 @@
namespace facebook::react {
namespace detail {
// Helper to detect if T is a Builder type.
// Builder types have: nested Input struct and buildUnsafeRawValue() method.
template <typename T, typename = void>
struct IsBuilder : std::false_type {};
template <typename T>
struct IsBuilder<T, std::void_t<typename T::Input, decltype(std::declval<T>().buildUnsafeRawValue())>>
: std::true_type {};
// Resolve Builder to its parent Constants type.
// For backwards compatibility: if T is a Builder type (e.g., JS::X::Constants::Builder),
// we resolve to the parent Constants type (JS::X::Constants).
//
// This requires Builder to have a type alias `using ResultT = Constants;` defined by codegen.
template <typename T, bool = IsBuilder<T>::value>
struct ResolveConstantsType {
// Not a Builder, use T as-is
using type = T;
};
// Specialization for Builder types that have ResultT defined
template <typename T>
struct ResolveConstantsType<T, true> {
// Use T::ResultT which points to the parent Constants type (added by codegen)
using type = typename T::ResultT;
};
} // namespace detail
// Objective-C doesn't allow arbitrary types in its lightweight generics, only object and block types. We can work
// around that by having the struct type we care about be a block-argument. The block never exists at runtime.
//
// For backwards compatibility: if T is a Builder type (e.g., JS::Module::Constants::Builder),
// ModuleConstants<Builder> resolves to the same type as ModuleConstants<Constants>.
template <typename T>
using ModuleConstants = _RCTTypedModuleConstants<void (^)(T)> *;
using ModuleConstants = _RCTTypedModuleConstants<void (^)(typename detail::ResolveConstantsType<T>::type)> *;
template <typename T>
ModuleConstants<T> typedConstants(typename T::Builder::Input &&value)
@@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN
namespace JS::NativeSampleTurboModule {
struct Constants {
struct Builder {
using ResultT = Constants;
struct Input {
RCTRequired<bool> const1;
RCTRequired<double> const2;