From 4fd8f405beaefdf897ee8e511542fca3d6d71728 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 4 May 2023 05:04:12 -0700 Subject: [PATCH] Recognize dictionary type in codegen (#37206) Summary: Previously we allow `{[key:string]:Something}` in codegen, `Something` is type-checked but thrown away, generating a `GenericObjectTypeAnnotation`. In this change, `Something` is added to `GenericObjectTypeAnnotation` as an optional field. For downstream code such as C++ codegen, this change is **backward compatible**. It allows C++ codegen to produce a more precious type optionally. ## Changelog: [General] [Added] - Recognize dictionary type in codegen Pull Request resolved: https://github.com/facebook/react-native/pull/37206 Test Plan: ``` yarn jest react-native-codegen yarn jest react-native-codegen-typescript-test ``` Reviewed By: cipolleschi Differential Revision: D45563340 Pulled By: dmytrorykun fbshipit-source-id: 9a9ce36df6ded6d42d35c3dcb6fb0eaca16c4458 --- .../src/CodegenSchema.d.ts | 1 + .../react-native-codegen/src/CodegenSchema.js | 5 +++ .../module-parser-snapshot-test.js.snap | 32 ++++++++++++++++--- .../src/parsers/flow/modules/index.js | 6 ++-- .../src/parsers/parsers-primitives.js | 11 +++++++ ...script-module-parser-snapshot-test.js.snap | 26 ++++++++++++--- .../src/parsers/typescript/modules/index.js | 6 ++-- 7 files changed, 72 insertions(+), 15 deletions(-) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 2c33b098ea4..3482172d990 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -295,6 +295,7 @@ export interface NativeModuleEnumDeclarationWithMembers { export interface NativeModuleGenericObjectTypeAnnotation { readonly type: 'GenericObjectTypeAnnotation'; + readonly dictionaryValueType?: Nullable | undefined; } export interface NativeModuleTypeAliasTypeAnnotation { diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 08b551a9a47..f05a4f2e749 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -328,6 +328,11 @@ export type NativeModuleEnumDeclarationWithMembers = { export type NativeModuleGenericObjectTypeAnnotation = $ReadOnly<{ type: 'GenericObjectTypeAnnotation', + + // a dictionary type is codegen as "Object" + // but we know all its members are in the same type + // when it happens, the following field is non-null + dictionaryValueType?: Nullable, }>; export type NativeModuleTypeAliasTypeAnnotation = $ReadOnly<{ diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap index 6de97cbbc6b..00d66fd81de 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap @@ -201,14 +201,26 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } } } ] @@ -220,14 +232,20 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } } } ] @@ -2165,7 +2183,11 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_ 'returnTypeAnnotation': { 'type': 'PromiseTypeAnnotation', 'elementType': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'CustomObject' + } } }, 'params': [] diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 1b7b2503f70..75352fea2bf 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -32,7 +32,7 @@ const { const { emitArrayType, emitFunction, - emitGenericObject, + emitDictionary, emitPromise, emitRootTag, emitUnion, @@ -152,7 +152,7 @@ function translateTypeAnnotation( // check the property type to prevent developers from using unsupported types // the return value from `translateTypeAnnotation` is unused const propertyType = indexers[0].value; - translateTypeAnnotation( + const valueType = translateTypeAnnotation( hasteModuleName, propertyType, types, @@ -163,7 +163,7 @@ function translateTypeAnnotation( parser, ); // no need to do further checking - return emitGenericObject(nullable); + return emitDictionary(nullable, valueType); } } diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 849c3e756fb..84ba85949d5 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -309,6 +309,16 @@ function emitGenericObject( }); } +function emitDictionary( + nullable: boolean, + valueType: Nullable, +): Nullable { + return wrapNullable(nullable, { + type: 'GenericObjectTypeAnnotation', + dictionaryValueType: valueType, + }); +} + function emitObject( nullable: boolean, properties: Array<$FlowFixMe>, @@ -576,6 +586,7 @@ module.exports = { emitInt32, emitNumber, emitGenericObject, + emitDictionary, emitObject, emitPromise, emitRootTag, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index 6f7033c9440..870a9349416 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -199,14 +199,26 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } } } ] @@ -218,14 +230,20 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } } } ] diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index d9e20011a18..6123cf4321a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -35,7 +35,7 @@ const {parseObjectProperty} = require('../../parsers-commons'); const { emitArrayType, emitFunction, - emitGenericObject, + emitDictionary, emitPromise, emitRootTag, emitUnion, @@ -309,7 +309,7 @@ function translateTypeAnnotation( // check the property type to prevent developers from using unsupported types // the return value from `translateTypeAnnotation` is unused const propertyType = indexSignatures[0].typeAnnotation; - translateTypeAnnotation( + const valueType = translateTypeAnnotation( hasteModuleName, propertyType, types, @@ -320,7 +320,7 @@ function translateTypeAnnotation( parser, ); // no need to do further checking - return emitGenericObject(nullable); + return emitDictionary(nullable, valueType); } }