From ab1b5ae6046b9caaee51e246cfa3b6b0777b1636 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Thu, 20 Nov 2025 12:48:21 -0800 Subject: [PATCH 1/2] Introduce BooleanLiteralTypeAnnotation (#54590) Summary: Introduce `BooleanLiteralTypeAnnotation` in Flow & TypeScript to match the existing `StringLiteralTypeAnnotation` & `NumberLiteralTypeAnnotation` since Unions will be supporting Booleans along with String & Number Changelog: [Internal] Reviewed By: elicwhite Differential Revision: D87384473 --- .../src/CodegenSchema.d.ts | 7 ++++++ .../react-native-codegen/src/CodegenSchema.js | 7 ++++++ .../src/generators/modules/GenerateModuleH.js | 4 ++++ .../modules/GenerateModuleJavaSpec.js | 7 ++++++ .../modules/GenerateModuleJniCpp.js | 6 +++++ .../GenerateModuleObjCpp/StructCollector.js | 2 ++ .../header/serializeConstantsStruct.js | 4 ++++ .../header/serializeRegularStruct.js | 4 ++++ .../serializeEventEmitter.js | 1 + .../GenerateModuleObjCpp/serializeMethod.js | 6 +++++ .../modules/__test_fixtures__/fixtures.js | 1 + .../module-parser-snapshot-test.js.snap | 20 ++++++++++++++++ .../src/parsers/flow/modules/index.js | 4 ++++ .../src/parsers/parsers-primitives.js | 12 ++++++++++ .../modules/__test_fixtures__/fixtures.js | 1 + ...script-module-parser-snapshot-test.js.snap | 20 ++++++++++++++++ .../src/parsers/typescript/modules/index.js | 4 ++++ .../src/ErrorFormatting.js | 2 ++ .../src/SortTypeAnnotations.js | 5 ++++ .../src/TypeDiffing.js | 22 +++++++++++++++++ .../src/__tests__/TypeDiffing-test.js | 24 +++++++++++++++++++ .../NativeTypeDiffingTypes.js.flow | 6 +++++ 22 files changed, 169 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index bc026fce48e7ad..1ec717bcf95597 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -46,6 +46,11 @@ export interface VoidTypeAnnotation { readonly type: 'VoidTypeAnnotation'; } +export interface BooleanLiteralTypeAnnotation { + readonly type: 'BooleanLiteralTypeAnnotation'; + readonly value: boolean; +} + export interface ObjectTypeAnnotation { readonly type: 'ObjectTypeAnnotation'; readonly properties: readonly NamedShape[]; @@ -399,6 +404,7 @@ export type NativeModuleEventEmitterBaseTypeAnnotation = | NativeModuleInt32TypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | NativeModuleStringTypeAnnotation | StringLiteralTypeAnnotation | StringLiteralUnionTypeAnnotation @@ -416,6 +422,7 @@ export type NativeModuleBaseTypeAnnotation = | StringLiteralUnionTypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | NativeModuleInt32TypeAnnotation | NativeModuleDoubleTypeAnnotation | NativeModuleFloatTypeAnnotation diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 98cf7af93960ab..a28f79c3a43b38 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -56,6 +56,11 @@ export type StringLiteralTypeAnnotation = $ReadOnly<{ value: string, }>; +export type BooleanLiteralTypeAnnotation = $ReadOnly<{ + type: 'BooleanLiteralTypeAnnotation', + value: boolean, +}>; + export type StringLiteralUnionTypeAnnotation = $ReadOnly<{ type: 'StringLiteralUnionTypeAnnotation', types: $ReadOnlyArray, @@ -388,6 +393,7 @@ type NativeModuleEventEmitterBaseTypeAnnotation = | Int32TypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | StringTypeAnnotation | StringLiteralTypeAnnotation | StringLiteralUnionTypeAnnotation @@ -405,6 +411,7 @@ export type NativeModuleBaseTypeAnnotation = | StringLiteralUnionTypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | Int32TypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 2779f16572e10d..9714de17029099 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -96,6 +96,8 @@ function serializeArg( return wrap(val => `${val}.asString(rt)`); case 'BooleanTypeAnnotation': return wrap(val => `${val}.asBool()`); + case 'BooleanLiteralTypeAnnotation': + return wrap(val => `${val}.asBool()`); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -265,6 +267,8 @@ function translatePrimitiveJSTypeToCpp( return wrapOptional('int', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('bool', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('bool', isRequired); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index e634125797cae6..af57a2f87bf0cf 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -142,6 +142,7 @@ function translateEventEmitterTypeToJavaType( case 'Int32TypeAnnotation': return 'double'; case 'BooleanTypeAnnotation': + case 'BooleanLiteralTypeAnnotation': return 'boolean'; case 'GenericObjectTypeAnnotation': case 'ObjectTypeAnnotation': @@ -214,6 +215,8 @@ function translateFunctionParamToJavaType( return wrapOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('boolean', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('boolean', isRequired); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -310,6 +313,8 @@ function translateFunctionReturnTypeToJavaType( return wrapOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('boolean', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('boolean', isRequired); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -388,6 +393,8 @@ function getFalsyReturnStatementFromReturnType( return nullable ? 'return null;' : 'return 0;'; case 'BooleanTypeAnnotation': return nullable ? 'return null;' : 'return false;'; + case 'BooleanLiteralTypeAnnotation': + return nullable ? 'return null;' : 'return false;'; case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index e9ece53f47d867..5098cef1585626 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -171,6 +171,8 @@ function translateReturnTypeToKind( return 'StringKind'; case 'BooleanTypeAnnotation': return 'BooleanKind'; + case 'BooleanLiteralTypeAnnotation': + return 'BooleanKind'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -256,6 +258,8 @@ function translateParamTypeToJniType( return 'Ljava/lang/String;'; case 'BooleanTypeAnnotation': return !isRequired ? 'Ljava/lang/Boolean;' : 'Z'; + case 'BooleanLiteralTypeAnnotation': + return !isRequired ? 'Ljava/lang/Boolean;' : 'Z'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -338,6 +342,8 @@ function translateReturnTypeToJniType( return 'Ljava/lang/String;'; case 'BooleanTypeAnnotation': return nullable ? 'Ljava/lang/Boolean;' : 'Z'; + case 'BooleanLiteralTypeAnnotation': + return nullable ? 'Ljava/lang/Boolean;' : 'Z'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index db243d9f3024a2..88ef558f40e0bc 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -11,6 +11,7 @@ 'use strict'; import type { + BooleanLiteralTypeAnnotation, BooleanTypeAnnotation, DoubleTypeAnnotation, FloatTypeAnnotation, @@ -65,6 +66,7 @@ export type StructTypeAnnotation = | StringLiteralUnionTypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | Int32TypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js index 9cee0665e8f396..807562b4c1b81b 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js @@ -110,6 +110,8 @@ function toObjCType( return wrapCxxOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapCxxOptional('bool', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapCxxOptional('bool', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -195,6 +197,8 @@ function toObjCValue( return wrapPrimitive('double'); case 'BooleanTypeAnnotation': return wrapPrimitive('BOOL'); + case 'BooleanLiteralTypeAnnotation': + return wrapPrimitive('BOOL'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js index 9fca06510ad933..576d71e3e29f28 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js @@ -101,6 +101,8 @@ function toObjCType( return wrapCxxOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapCxxOptional('bool', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapCxxOptional('bool', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -185,6 +187,8 @@ function toObjCValue( return RCTBridgingTo('Double'); case 'BooleanTypeAnnotation': return RCTBridgingTo('Bool'); + case 'BooleanLiteralTypeAnnotation': + return RCTBridgingTo('Bool'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js index fd1afff066fbf7..41043edf71a8d7 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js @@ -28,6 +28,7 @@ function getEventEmitterTypeObjCType( case 'NumberLiteralTypeAnnotation': return 'NSNumber *_Nonnull'; case 'BooleanTypeAnnotation': + case 'BooleanLiteralTypeAnnotation': return 'BOOL'; case 'GenericObjectTypeAnnotation': case 'ObjectTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index 8e0a56472ff8b3..d27aba65635a36 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -273,6 +273,8 @@ function getParamObjCType( return notStruct(isRequired ? 'NSInteger' : 'NSNumber *'); case 'BooleanTypeAnnotation': return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); + case 'BooleanLiteralTypeAnnotation': + return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -356,6 +358,8 @@ function getReturnObjCType( return wrapOptional('NSNumber *', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('NSNumber *', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('NSNumber *', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -428,6 +432,8 @@ function getReturnJSType( return 'NumberKind'; case 'BooleanTypeAnnotation': return 'BooleanKind'; + case 'BooleanLiteralTypeAnnotation': + return 'BooleanKind'; case 'GenericObjectTypeAnnotation': return 'ObjectKind'; case 'EnumDeclaration': diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js index f87e0d676838af..9edf171d7b7364 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js @@ -126,6 +126,7 @@ import * as TurboModuleRegistry from '../TurboModuleRegistry'; export interface Spec extends TurboModule { +passBool?: (arg: boolean) => void; +passNumber: (arg: number) => void; + +passBooleanLiteral: (arg: true) => void; +passNumberLiteral: (arg: 4) => void; +passString: (arg: string) => void; +passStringish: (arg: Stringish) => void; 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 d76198a01b8431..c4a5e99b641efd 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 @@ -1252,6 +1252,26 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA ] } }, + { + 'name': 'passBooleanLiteral', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'arg', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanLiteralTypeAnnotation', + 'value': true + } + } + ] + } + }, { 'name': 'passNumberLiteral', 'optional': false, 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 51972f39ae03f6..d28cb3cc85fa51 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -35,6 +35,7 @@ const { } = require('../../parsers-commons'); const { emitArrayType, + emitBooleanLiteral, emitCommonTypes, emitDictionary, emitFunction, @@ -249,6 +250,9 @@ function translateTypeAnnotation( case 'NumberLiteralTypeAnnotation': { return emitNumberLiteral(nullable, typeAnnotation.value); } + case 'BooleanLiteralTypeAnnotation': { + return emitBooleanLiteral(nullable, typeAnnotation.value); + } case 'StringLiteralTypeAnnotation': { return wrapNullable(nullable, { type: 'StringLiteralTypeAnnotation', diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 27097a0b0b6f09..b6d496de37e1bd 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -11,6 +11,7 @@ 'use strict'; import type { + BooleanLiteralTypeAnnotation, BooleanTypeAnnotation, DoubleTypeAnnotation, EventTypeAnnotation, @@ -181,6 +182,16 @@ function emitNumberLiteral( }); } +function emitBooleanLiteral( + nullable: boolean, + value: boolean, +): Nullable { + return wrapNullable(nullable, { + type: 'BooleanLiteralTypeAnnotation', + value, + }); +} + function emitString(nullable: boolean): Nullable { return wrapNullable(nullable, { type: 'StringTypeAnnotation', @@ -764,6 +775,7 @@ function emitUnionProp( module.exports = { emitArrayType, emitBoolean, + emitBooleanLiteral, emitBoolProp, emitDouble, emitDoubleProp, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js index 927963069a9ac0..9f10cc5b5aa63e 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js @@ -113,6 +113,7 @@ import * as TurboModuleRegistry from '../TurboModuleRegistry'; export interface Spec extends TurboModule { readonly passBool?: (arg: boolean) => void; readonly passNumber: (arg: number) => void; + readonly passBooleanLiteral: (arg: true) => void; readonly passNumberLiteral: (arg: 4) => void; readonly passString: (arg: string) => void; readonly passStringish: (arg: Stringish) => void; 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 7ab0aaad678018..ce87f6baff8b9c 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 @@ -1393,6 +1393,26 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BA ] } }, + { + 'name': 'passBooleanLiteral', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'arg', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanLiteralTypeAnnotation', + 'value': true + } + } + ] + } + }, { 'name': 'passNumberLiteral', 'optional': false, 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 15f96966660d6b..c416462e776a47 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -34,6 +34,7 @@ const { const {parseObjectProperty} = require('../../parsers-commons'); const { emitArrayType, + emitBooleanLiteral, emitCommonTypes, emitDictionary, emitFunction, @@ -409,6 +410,9 @@ function translateTypeAnnotation( case 'NumericLiteral': { return emitNumberLiteral(nullable, literal.value); } + case 'BooleanLiteral': { + return emitBooleanLiteral(nullable, literal.value); + } default: { throw new UnsupportedTypeAnnotationParserError( hasteModuleName, diff --git a/packages/react-native-compatibility-check/src/ErrorFormatting.js b/packages/react-native-compatibility-check/src/ErrorFormatting.js index 91e77078cf08a2..ec557505767a6e 100644 --- a/packages/react-native-compatibility-check/src/ErrorFormatting.js +++ b/packages/react-native-compatibility-check/src/ErrorFormatting.js @@ -173,6 +173,8 @@ function formatTypeAnnotation(annotation: CompleteTypeAnnotation): string { return 'int'; case 'NumberLiteralTypeAnnotation': return annotation.value.toString(); + case 'BooleanLiteralTypeAnnotation': + return annotation.value.toString(); case 'ObjectTypeAnnotation': return ( '{' + diff --git a/packages/react-native-compatibility-check/src/SortTypeAnnotations.js b/packages/react-native-compatibility-check/src/SortTypeAnnotations.js index 142581169de0ac..a82c1e393495ee 100644 --- a/packages/react-native-compatibility-check/src/SortTypeAnnotations.js +++ b/packages/react-native-compatibility-check/src/SortTypeAnnotations.js @@ -116,6 +116,9 @@ export function compareTypeAnnotationForSorting( case 'NumberLiteralTypeAnnotation': invariant(typeB.type === 'NumberLiteralTypeAnnotation', EQUALITY_MSG); return typeA.value - typeB.value; + case 'BooleanLiteralTypeAnnotation': + invariant(typeB.type === 'BooleanLiteralTypeAnnotation', EQUALITY_MSG); + return originalPositionA - originalPositionB; case 'ObjectTypeAnnotation': invariant(typeB.type === 'ObjectTypeAnnotation', EQUALITY_MSG); return compareNameAnnotationArraysForSorting( @@ -261,6 +264,8 @@ function typeAnnotationArbitraryOrder(annotation: CompleteTypeAnnotation) { return 14; case 'ObjectTypeAnnotation': return 15; + case 'BooleanLiteralTypeAnnotation': + return 16; case 'StringLiteralUnionTypeAnnotation': return 17; case 'StringTypeAnnotation': diff --git a/packages/react-native-compatibility-check/src/TypeDiffing.js b/packages/react-native-compatibility-check/src/TypeDiffing.js index 49a0202e07a351..f86ba95981ffb1 100644 --- a/packages/react-native-compatibility-check/src/TypeDiffing.js +++ b/packages/react-native-compatibility-check/src/TypeDiffing.js @@ -17,6 +17,7 @@ import type { TypeComparisonError, } from './ComparisonResult'; import type { + BooleanLiteralTypeAnnotation, CompleteReservedTypeAnnotation, CompleteTypeAnnotation, EventEmitterTypeAnnotation, @@ -237,6 +238,12 @@ export function compareTypeAnnotation( EQUALITY_MSG, ); return compareNumberLiteralTypes(newerAnnotation, olderAnnotation); + case 'BooleanLiteralTypeAnnotation': + invariant( + olderAnnotation.type === 'BooleanLiteralTypeAnnotation', + EQUALITY_MSG, + ); + return compareBooleanLiteralTypes(newerAnnotation, olderAnnotation); case 'StringLiteralUnionTypeAnnotation': invariant( olderAnnotation.type === 'StringLiteralUnionTypeAnnotation', @@ -907,6 +914,21 @@ export function compareStringLiteralTypes( ); } +export function compareBooleanLiteralTypes( + newerType: BooleanLiteralTypeAnnotation, + olderType: BooleanLiteralTypeAnnotation, +): ComparisonResult { + return newerType.value === olderType.value + ? {status: 'matching'} + : makeError( + typeAnnotationComparisonError( + 'Boolean literals are not equal', + newerType, + olderType, + ), + ); +} + export function compareStringLiteralUnionTypes( newerType: StringLiteralUnionTypeAnnotation, olderType: StringLiteralUnionTypeAnnotation, diff --git a/packages/react-native-compatibility-check/src/__tests__/TypeDiffing-test.js b/packages/react-native-compatibility-check/src/__tests__/TypeDiffing-test.js index 563d89997f2ed5..604868bf68ba97 100644 --- a/packages/react-native-compatibility-check/src/__tests__/TypeDiffing-test.js +++ b/packages/react-native-compatibility-check/src/__tests__/TypeDiffing-test.js @@ -905,6 +905,30 @@ describe('compareTypes on string literals', () => { }); }); +describe('compareTypes on boolean literals', () => { + it('matches literals that are the same', () => { + expect( + compareTypes( + nativeTypeDiffingTypesMethodParamLookup('booleanLiteral0'), + nativeTypeDiffingTypesMethodParamLookup('booleanLiteral0'), + nativeTypeDiffingTypesAliases, + nativeTypeDiffingTypesAliases, + ).status, + ).toBe('matching'); + }); + + it('fails on literals that are not the same', () => { + expect( + compareTypes( + nativeTypeDiffingTypesMethodParamLookup('booleanLiteral0'), + nativeTypeDiffingTypesMethodParamLookup('booleanLiteral1'), + nativeTypeDiffingTypesAliases, + nativeTypeDiffingTypesAliases, + ), + ).toHaveErrorWithMessage('Boolean literals are not equal'); + }); +}); + describe('compareTypes on numeric literals', () => { it('matches literals that are the same', () => { expect( diff --git a/packages/react-native-compatibility-check/src/__tests__/__fixtures__/native-module-type-diffing-types/NativeTypeDiffingTypes.js.flow b/packages/react-native-compatibility-check/src/__tests__/__fixtures__/native-module-type-diffing-types/NativeTypeDiffingTypes.js.flow index a215dd4bf21ef1..a3fccd7a0e1f33 100644 --- a/packages/react-native-compatibility-check/src/__tests__/__fixtures__/native-module-type-diffing-types/NativeTypeDiffingTypes.js.flow +++ b/packages/react-native-compatibility-check/src/__tests__/__fixtures__/native-module-type-diffing-types/NativeTypeDiffingTypes.js.flow @@ -17,6 +17,9 @@ import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboMo type StringLiteral0 = 'foo'; type StringLiteral1 = 'bar'; +type BooleanLiteral0 = true; +type BooleanLiteral1 = false; + type NumericLiteral0 = 1; type NumericLiteral1 = 2; @@ -170,6 +173,9 @@ export interface Spec extends TurboModule { +stringLiteral0: (a: StringLiteral0) => void; +stringLiteral1: (a: StringLiteral1) => void; + +booleanLiteral0: (a: BooleanLiteral0) => void; + +booleanLiteral1: (a: BooleanLiteral1) => void; + +numericLiteral0: (a: NumericLiteral0) => void; +numericLiteral1: (a: NumericLiteral1) => void; From e5fa3506ee91d4cb23d63a27bc91c489cb360f50 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Thu, 20 Nov 2025 12:48:21 -0800 Subject: [PATCH 2/2] Introduce the supported member types of Union (#54591) Summary: Following types will be supported in Union currently: 1. Number : NumberType + NumberLiteralType 2. Boolean : BooleanType + BooleanLiteralType 3. String : StringType + StringLiteralType 4. Object: NativeModuleObjectType These are the only ones that exist today as per : https://docs.google.com/document/d/1pTBMOEIov5n5-0L9z925XPvGX1YxlmI6n6FJvd0oXtE/edit?tab=t.0#heading=h.fhe5py9plytd Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D87384995 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 9 +++++++++ packages/react-native-codegen/src/CodegenSchema.js | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 1ec717bcf95597..f064ad55a2d24a 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -388,6 +388,15 @@ export type UnionTypeAnnotationMemberType = | 'ObjectTypeAnnotation' | 'StringTypeAnnotation'; +export type NativeModuleUnionTypeAnnotationMemberType = + | NativeModuleObjectTypeAnnotation + | StringLiteralTypeAnnotation + | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation + | BooleanTypeAnnotation + | StringTypeAnnotation + | NumberTypeAnnotation; + export interface NativeModuleUnionTypeAnnotation { readonly type: 'UnionTypeAnnotation'; readonly memberType: UnionTypeAnnotationMemberType; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index a28f79c3a43b38..099404b22d97af 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -377,6 +377,15 @@ export type UnionTypeAnnotationMemberType = | 'ObjectTypeAnnotation' | 'StringTypeAnnotation'; +export type NativeModuleUnionTypeAnnotationMemberType = + | NativeModuleObjectTypeAnnotation + | StringLiteralTypeAnnotation + | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation + | BooleanTypeAnnotation + | StringTypeAnnotation + | NumberTypeAnnotation; + export type NativeModuleUnionTypeAnnotation = $ReadOnly<{ type: 'UnionTypeAnnotation', memberType: UnionTypeAnnotationMemberType,