simple support to the Partial<T> annotation (#35961)

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

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

This fixes #35864

This feature allows using `$Partial<Obj>` in flow and `Partial<Obj>` in TypeScript based on the spec mentioned here: https://flow.org/en/docs/types/utilities/#toc-partial.

We currently only allow passing an Obj to Partial so
```
export type SomeObj = {
  a: string,
  b?: boolean,
};

export type PartialSomeObj = Partial<SomeObj>;
```
should work.
and also-
```
export type PartialSomeObj = Partial<{
  a: string,
  b?: boolean,
}>;
```
But not
```
export type PartialSomeObj = Partial<Partial<{
  a: string,
  b?: boolean,
}>>;
```
This can be improved in the future by a recursive unwrapping of the value inside the `Partial` annotation.

Changelog:
[General] [Added] -  Allow the use of "Partial<T>" in Turbo Module specs.

Reviewed By: christophpurrer, cipolleschi

Differential Revision: D42640880

fbshipit-source-id: 03a3fccc38ccfc7a5440fe11893beb68e77753f3
This commit is contained in:
Vitali Zaidman
2023-01-26 12:30:38 -08:00
committed by Facebook GitHub Bot
parent 53932d0022
commit 97e707d897
10 changed files with 985 additions and 18 deletions
@@ -0,0 +1,35 @@
/**
* 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
*/
'use strict';
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export type SomeObj = {|
a: string,
b?: boolean,
|};
export type PartialSomeObj = $Partial<SomeObj>;
export interface Spec extends TurboModule {
+getSomeObj: () => SomeObj;
+getPartialSomeObj: () => $Partial<SomeObj>;
+getSomeObjFromPartialSomeObj: (value: $Partial<SomeObj>) => SomeObj;
+getPartialPartial: (
value1: $Partial<SomeObj>,
value2: PartialSomeObj,
) => SomeObj;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativePartialAnnotationTurboModule',
): Spec);
@@ -430,6 +430,74 @@ namespace facebook {
};
} // namespace react
} // namespace facebook
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetSomeObjFromPartialSomeObjValue {
NSString *a() const;
std::optional<bool> b() const;
SpecGetSomeObjFromPartialSomeObjValue(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json;
@end
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetPartialPartialValue1 {
NSString *a() const;
std::optional<bool> b() const;
SpecGetPartialPartialValue1(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json;
@end
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetPartialPartialValue2 {
NSString *a() const;
std::optional<bool> b() const;
SpecGetPartialPartialValue2(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json;
@end
@protocol NativePartialAnnotationTurboModuleSpec <RCTBridgeModule, RCTTurboModule>
- (NSDictionary *)getSomeObj;
- (NSDictionary *)getPartialSomeObj;
- (NSDictionary *)getSomeObjFromPartialSomeObj:(JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue &)value;
- (NSDictionary *)getPartialPartial:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1 &)value1
value2:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2 &)value2;
@end
namespace facebook {
namespace react {
/**
* ObjC++ class for module 'NativePartialAnnotationTurboModule'
*/
class JSI_EXPORT NativePartialAnnotationTurboModuleSpecJSI : public ObjCTurboModule {
public:
NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams &params);
};
} // namespace react
} // namespace facebook
@protocol NativePromiseTurboModuleSpec <RCTBridgeModule, RCTTurboModule>
@@ -1069,6 +1137,36 @@ inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(const In
inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(Constants i) : _factory(^{
return i.unsafeRawValue();
}) {}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline double JS::NativeSampleTurboModule::SpecGetObjectShapeArg::prop() const
{
@@ -1622,6 +1720,74 @@ namespace facebook {
};
} // namespace react
} // namespace facebook
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetSomeObjFromPartialSomeObjValue {
NSString *a() const;
std::optional<bool> b() const;
SpecGetSomeObjFromPartialSomeObjValue(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json;
@end
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetPartialPartialValue1 {
NSString *a() const;
std::optional<bool> b() const;
SpecGetPartialPartialValue1(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json;
@end
namespace JS {
namespace NativePartialAnnotationTurboModule {
struct SpecGetPartialPartialValue2 {
NSString *a() const;
std::optional<bool> b() const;
SpecGetPartialPartialValue2(NSDictionary *const v) : _v(v) {}
private:
NSDictionary *_v;
};
}
}
@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json;
@end
@protocol NativePartialAnnotationTurboModuleSpec <RCTBridgeModule, RCTTurboModule>
- (NSDictionary *)getSomeObj;
- (NSDictionary *)getPartialSomeObj;
- (NSDictionary *)getSomeObjFromPartialSomeObj:(JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue &)value;
- (NSDictionary *)getPartialPartial:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1 &)value1
value2:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2 &)value2;
@end
namespace facebook {
namespace react {
/**
* ObjC++ class for module 'NativePartialAnnotationTurboModule'
*/
class JSI_EXPORT NativePartialAnnotationTurboModuleSpecJSI : public ObjCTurboModule {
public:
NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams &params);
};
} // namespace react
} // namespace facebook
@protocol NativePromiseTurboModuleSpec <RCTBridgeModule, RCTTurboModule>
@@ -2261,6 +2427,36 @@ inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(const In
inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(Constants i) : _factory(^{
return i.unsafeRawValue();
}) {}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::a() const
{
id const p = _v[@\\"a\\"];
return RCTBridgingToOptionalString(p);
}
inline std::optional<bool> JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::b() const
{
id const p = _v[@\\"b\\"];
return RCTBridgingToOptionalBool(p);
}
inline double JS::NativeSampleTurboModule::SpecGetObjectShapeArg::prop() const
{
@@ -2620,6 +2816,61 @@ namespace facebook {
}
} // namespace react
} // namespace facebook
@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json
{
return facebook::react::managedPointer<JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue>(json);
}
@end
@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json
{
return facebook::react::managedPointer<JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1>(json);
}
@end
@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2)
+ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json
{
return facebook::react::managedPointer<JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2>(json);
}
@end
namespace facebook {
namespace react {
static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getSomeObj\\", @selector(getSomeObj), args, count);
}
static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getPartialSomeObj\\", @selector(getPartialSomeObj), args, count);
}
static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObjFromPartialSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getSomeObjFromPartialSomeObj\\", @selector(getSomeObjFromPartialSomeObj:), args, count);
}
static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialPartial(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getPartialPartial\\", @selector(getPartialPartial:value2:), args, count);
}
NativePartialAnnotationTurboModuleSpecJSI::NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams &params)
: ObjCTurboModule(params) {
methodMap_[\\"getSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObj};
methodMap_[\\"getPartialSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialSomeObj};
methodMap_[\\"getSomeObjFromPartialSomeObj\\"] = MethodMetadata {1, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObjFromPartialSomeObj};
setMethodArgConversionSelector(@\\"getSomeObjFromPartialSomeObj\\", 0, @\\"JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:\\");
methodMap_[\\"getPartialPartial\\"] = MethodMetadata {2, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialPartial};
setMethodArgConversionSelector(@\\"getPartialPartial\\", 0, @\\"JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:\\");
setMethodArgConversionSelector(@\\"getPartialPartial\\", 1, @\\"JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:\\");
}
} // namespace react
} // namespace facebook
namespace facebook {
namespace react {
@@ -21,6 +21,7 @@ const {
emitNumber,
emitInt32,
emitObject,
emitPartial,
emitPromise,
emitRootTag,
emitVoid,
@@ -454,30 +455,94 @@ describe('emitObject', () => {
expect(result).toEqual(expected);
});
});
});
describe('emitFloat', () => {
describe('when nullable is true', () => {
it('returns nullable type annotation', () => {
const result = emitFloat(true);
const expected = {
type: 'NullableTypeAnnotation',
describe('emitPartial', () => {
describe('when nullable is true', () => {
it('returns nullable type annotation', () => {
const props = [
{
name: 'a',
optional: true,
typeAnnotation: {
type: 'FloatTypeAnnotation',
type: 'StringTypeAnnotation',
},
};
},
{
name: 'b',
optional: true,
typeAnnotation: {
type: 'BooleanTypeAnnotation',
},
},
];
expect(result).toEqual(expected);
});
const result = emitPartial(true, props);
const expected = {
type: 'NullableTypeAnnotation',
typeAnnotation: {
type: 'ObjectTypeAnnotation',
properties: props,
},
};
expect(result).toEqual(expected);
});
describe('when nullable is false', () => {
it('returns non nullable type annotation', () => {
const result = emitFloat(false);
const expected = {
type: 'FloatTypeAnnotation',
};
});
describe('when nullable is false', () => {
it('returns non nullable type annotation', () => {
const props = [
{
name: 'a',
optional: true,
typeAnnotation: {
type: 'StringTypeAnnotation',
},
},
{
name: 'b',
optional: true,
typeAnnotation: {
type: 'BooleanTypeAnnotation',
},
},
];
expect(result).toEqual(expected);
});
const result = emitPartial(false, props);
const expected = {
type: 'ObjectTypeAnnotation',
properties: props,
};
expect(result).toEqual(expected);
});
});
});
describe('emitFloat', () => {
describe('when nullable is true', () => {
it('returns nullable type annotation', () => {
const result = emitFloat(true);
const expected = {
type: 'NullableTypeAnnotation',
typeAnnotation: {
type: 'FloatTypeAnnotation',
},
};
expect(result).toEqual(expected);
});
});
describe('when nullable is false', () => {
it('returns non nullable type annotation', () => {
const result = emitFloat(false);
const expected = {
type: 'FloatTypeAnnotation',
};
expect(result).toEqual(expected);
});
});
});
@@ -288,6 +288,68 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_PARTIALS = `
/**
* 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
*/
'use strict';
import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';
export type SomeObj = {|
a: string,
b?: boolean,
|};
export interface Spec extends TurboModule {
+getSomeObj: () => SomeObj;
+getPartialSomeObj: () => $Partial<SomeObj>;
+getSomeObjFromPartialSomeObj: (value: $Partial<SomeObj>) => SomeObj;
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_PARTIALS_COMPLEX = `
/**
* 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
*/
'use strict';
import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';
export type SomeObj = {|
a: string,
b?: boolean,
|};
export type PartialSomeObj = $Partial<SomeObj>;
export interface Spec extends TurboModule {
+getPartialPartial: (value1: $Partial<SomeObj>, value2: PartialSomeObj) => SomeObj
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_ROOT_TAG = `
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -732,6 +794,8 @@ module.exports = {
NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY,
NATIVE_MODULE_WITH_SIMPLE_OBJECT,
NATIVE_MODULE_WITH_UNSAFE_OBJECT,
NATIVE_MODULE_WITH_PARTIALS,
NATIVE_MODULE_WITH_PARTIALS_COMPLEX,
NATIVE_MODULE_WITH_ROOT_TAG,
NATIVE_MODULE_WITH_NULLABLE_PARAM,
NATIVE_MODULE_WITH_BASIC_ARRAY,
@@ -1431,6 +1431,212 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W
}"
`;
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 1`] = `
"{
'modules': {
'NativeSampleTurboModule': {
'type': 'NativeModule',
'aliases': {
'SomeObj': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
'spec': {
'properties': [
{
'name': 'getSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': []
}
},
{
'name': 'getPartialSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
},
'params': []
}
},
{
'name': 'getSomeObjFromPartialSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': [
{
'name': 'value',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
}
]
}
}
]
},
'moduleName': 'SampleTurboModule'
}
}
}"
`;
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS_COMPLEX 1`] = `
"{
'modules': {
'NativeSampleTurboModule': {
'type': 'NativeModule',
'aliases': {
'SomeObj': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
'spec': {
'properties': [
{
'name': 'getPartialPartial',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': [
{
'name': 'value1',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
{
'name': 'value2',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
}
]
}
}
]
},
'moduleName': 'SampleTurboModule'
}
}
}"
`;
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = `
"{
'modules': {
@@ -42,6 +42,7 @@ const {
emitNumber,
emitInt32,
emitObject,
emitPartial,
emitPromise,
emitRootTag,
emitVoid,
@@ -155,6 +156,40 @@ function translateTypeAnnotation(
case 'Object': {
return emitObject(nullable);
}
case '$Partial': {
if (typeAnnotation.typeParameters.params.length !== 1) {
throw new Error(
'Partials only support annotating exactly one parameter.',
);
}
const annotatedElement =
types[typeAnnotation.typeParameters.params[0].id.name];
if (!annotatedElement) {
throw new Error(
'Partials only support annotating a type parameter.',
);
}
const properties = annotatedElement.right.properties.map(prop => {
return {
name: prop.key.name,
optional: true,
typeAnnotation: translateTypeAnnotation(
hasteModuleName,
prop.value,
types,
aliasMap,
tryParse,
cxxOnly,
parser,
),
};
});
return emitPartial(nullable, properties);
}
default: {
return translateDefault(
hasteModuleName,
@@ -30,6 +30,7 @@ import type {
ReservedTypeAnnotation,
StringTypeAnnotation,
VoidTypeAnnotation,
NativeModuleObjectTypeAnnotation,
} from '../CodegenSchema';
import type {Parser} from './parser';
import type {
@@ -243,6 +244,16 @@ function emitObject(
});
}
function emitPartial(
nullable: boolean,
properties: Array<$FlowFixMe>,
): Nullable<NativeModuleObjectTypeAnnotation> {
return wrapNullable(nullable, {
type: 'ObjectTypeAnnotation',
properties,
});
}
function emitFloat(
nullable: boolean,
): Nullable<NativeModuleFloatTypeAnnotation> {
@@ -370,6 +381,7 @@ module.exports = {
emitInt32,
emitNumber,
emitObject,
emitPartial,
emitPromise,
emitRootTag,
emitVoid,
@@ -302,6 +302,60 @@ export interface Spec extends TurboModule {
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_PARTIALS = `
/**
* 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.
*
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export type SomeObj = {
a: string,
b?: boolean,
};
export interface Spec extends TurboModule {
getSomeObj: () => SomeObj;
getPartialSomeObj: () => Partial<SomeObj>;
getSomeObjFromPartialSomeObj: (value: Partial<SomeObj>) => SomeObj;
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_PARTIALS_COMPLEX = `
/**
* 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.
*
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export type SomeObj = {
a: string,
b?: boolean,
};
export type PartialSomeObj = Partial<SomeObj>;
export interface Spec extends TurboModule {
getPartialPartial: (value1: Partial<SomeObj>, value2: PartialSomeObj) => SomeObj;
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_ROOT_TAG = `
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -754,6 +808,8 @@ module.exports = {
NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY,
NATIVE_MODULE_WITH_SIMPLE_OBJECT,
NATIVE_MODULE_WITH_UNSAFE_OBJECT,
NATIVE_MODULE_WITH_PARTIALS,
NATIVE_MODULE_WITH_PARTIALS_COMPLEX,
NATIVE_MODULE_WITH_ROOT_TAG,
NATIVE_MODULE_WITH_NULLABLE_PARAM,
NATIVE_MODULE_WITH_BASIC_ARRAY,
@@ -1737,6 +1737,212 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_OB
}"
`;
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 1`] = `
"{
'modules': {
'NativeSampleTurboModule': {
'type': 'NativeModule',
'aliases': {
'SomeObj': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
'spec': {
'properties': [
{
'name': 'getSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': []
}
},
{
'name': 'getPartialSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
},
'params': []
}
},
{
'name': 'getSomeObjFromPartialSomeObj',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': [
{
'name': 'value',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
}
]
}
}
]
},
'moduleName': 'SampleTurboModule'
}
}
}"
`;
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS_COMPLEX 1`] = `
"{
'modules': {
'NativeSampleTurboModule': {
'type': 'NativeModule',
'aliases': {
'SomeObj': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
'spec': {
'properties': [
{
'name': 'getPartialPartial',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'SomeObj'
},
'params': [
{
'name': 'value1',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
},
{
'name': 'value2',
'optional': false,
'typeAnnotation': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'a',
'optional': true,
'typeAnnotation': {
'type': 'StringTypeAnnotation'
}
},
{
'name': 'b',
'optional': true,
'typeAnnotation': {
'type': 'BooleanTypeAnnotation'
}
}
]
}
}
]
}
}
]
},
'moduleName': 'SampleTurboModule'
}
}
}"
`;
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = `
"{
'modules': {
@@ -42,6 +42,7 @@ const {
emitNumber,
emitInt32,
emitObject,
emitPartial,
emitPromise,
emitRootTag,
emitVoid,
@@ -172,6 +173,42 @@ function translateTypeAnnotation(
case 'Object': {
return emitObject(nullable);
}
case 'Partial': {
if (typeAnnotation.typeParameters.params.length !== 1) {
throw new Error(
'Partials only support annotating exactly one parameter.',
);
}
const annotatedElement =
types[typeAnnotation.typeParameters.params[0].typeName.name];
if (!annotatedElement) {
throw new Error(
'Partials only support annotating a type parameter.',
);
}
const properties = annotatedElement.typeAnnotation.members.map(
member => {
return {
name: member.key.name,
optional: true,
typeAnnotation: translateTypeAnnotation(
hasteModuleName,
member.typeAnnotation.typeAnnotation,
types,
aliasMap,
tryParse,
cxxOnly,
parser,
),
};
},
);
return emitPartial(nullable, properties);
}
default: {
return translateDefault(
hasteModuleName,