Turbo module codegen support interface with inheritance in module (#36011)

Summary:
The [previous pull request](https://github.com/facebook/react-native/pull/35812) enables defining interfaces and using them in a turbo module, but all members are flattened, this is not the best option for codegen for object oriented languages.

In this pull request, an optional member `baseTypes` is added to aliased objects. Members are still flattened for backward compatibility, if a codegen doesn't care about that nothing needs to be changed.

### Example

```typescript
interface A {
  a : string;
}

interface B extends A {
  b : number;
}
```

#### Before the previous pull request

`interface` is not allowed here, you must use type alias.

#### At the previous pull request

`interface` is allowed, but it is translated to

```typescript
type A = {a : string};
type B = {a : string, b : number};
```

#### At this pull request

Extra information is provided so that you know `B` extends `A`. By comparing `B` to `A` it is easy to know that `B::a` is obtained from `A`.

## Changelog

[GENERAL] [CHANGED] - Turbo module codegen support interface with inheritance in module

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

Test Plan: `yarn jest react-native-codegen` passed

Reviewed By: rshest

Differential Revision: D42882650

Pulled By: cipolleschi

fbshipit-source-id: 32d502e8a99c4151fae0a1f4dfa60db9ac827963
This commit is contained in:
Zihan Chen (MSFT)
2023-01-31 12:05:46 -08:00
committed by Facebook GitHub Bot
parent 597a1ff60b
commit bf34810c5c
3 changed files with 84 additions and 1 deletions
+3
View File
@@ -53,6 +53,9 @@ export type VoidTypeAnnotation = $ReadOnly<{
export type ObjectTypeAnnotation<+T> = $ReadOnly<{
type: 'ObjectTypeAnnotation',
properties: $ReadOnlyArray<NamedShape<T>>,
// metadata for objects that generated from interfaces
baseTypes?: $ReadOnlyArray<string>,
}>;
type FunctionTypeAnnotation<+P, +R> = $ReadOnly<{
@@ -1521,6 +1521,56 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE
}
]
},
'Base1': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'bar1',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'Bar'
}
}
]
},
'Base2': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'bar2',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'Bar'
}
}
]
},
'Base3': {
'type': 'ObjectTypeAnnotation',
'properties': [
{
'name': 'bar2',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'Bar'
}
},
{
'name': 'bar3',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'Bar'
}
}
],
'baseTypes': [
'Base2'
]
},
'Foo': {
'type': 'ObjectTypeAnnotation',
'properties': [
@@ -1556,6 +1606,10 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE
'name': 'Bar'
}
}
],
'baseTypes': [
'Base1',
'Base3'
]
}
},
@@ -221,7 +221,26 @@ function translateTypeAnnotation(
}
}
case 'TSInterfaceDeclaration': {
const objectTypeAnnotation = {
const baseTypes = (typeAnnotation.extends ?? []).map(
extend => extend.expression.name,
);
for (const baseType of baseTypes) {
// ensure base types exist and appear in aliasMap
translateTypeAnnotation(
hasteModuleName,
{
type: 'TSTypeReference',
typeName: {type: 'Identifier', name: baseType},
},
types,
aliasMap,
tryParse,
cxxOnly,
parser,
);
}
let objectTypeAnnotation = {
type: 'ObjectTypeAnnotation',
// $FlowFixMe[missing-type-arg]
properties: (flattenProperties(
@@ -246,8 +265,15 @@ function translateTypeAnnotation(
},
)
.filter(Boolean),
baseTypes,
};
if (objectTypeAnnotation.baseTypes.length === 0) {
// The flow checker does not allow adding a member after an object literal is created
// so here I do it in a reverse way
delete objectTypeAnnotation.baseTypes;
}
return typeAliasResolution(
typeAliasResolutionStatus,
objectTypeAnnotation,