Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,26 @@ describe('emitUnion', () => {
});
});

describe("when 'typeAnnotation.id.name' is 'LegacyObject'", () => {
const typeAnnotation = {
typeParameters: {
params: [1, 2],
type: 'GenericObjectTypeAnnotation',
},
id: {
name: 'LegacyObject',
},
};
const expected = {
type: 'GenericObjectTypeAnnotation',
};
const result = emitCommonTypesForUnitTest(typeAnnotation, false);

it("returns 'GenericObjectTypeAnnotation'", () => {
expect(result).toEqual(expected);
});
});

describe("when 'typeAnnotation.id.name' is 'Object'", () => {
const typeAnnotation = {
typeParameters: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ function emitCommonTypes(
Double: emitDouble,
Float: emitFloat,
UnsafeObject: emitGenericObject,
LegacyObject: emitGenericObject,
Object: emitGenericObject,
$Partial: emitPartial,
Partial: emitPartial,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-native-codegen/src/parsers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ function extractNativeModuleName(filename: string): string {
export type ParserErrorCapturer = <T>(fn: () => T) => ?T;

// $FlowFixMe[unclear-type] there's no flowtype for ASTs
export type PropAST = Object;
export type PropAST = any;

// $FlowFixMe[unclear-type] there's no flowtype for ASTs
export type ASTNode = Object;
export type ASTNode = any;

function createParserErrorCapturer(): [
Array<ParserError>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export type {EventSubscription, EmitterSubscription};
/** @deprecated Use `EventSubscription` instead. */
export type NativeEventSubscription = EventSubscription;

// $FlowFixMe[unclear-type] unclear type of events
type UnsafeNativeEventObject = Object;
type UnsafeNativeEventObject = LegacyObject;

/**
* `NativeEventEmitter` is intended for use by Native Modules to emit events to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ export interface PushNotification {
/**
* An alias for `getAlert` to get the notification's main message string
*/
// $FlowFixMe[unclear-type]
getMessage(): ?string | ?Object;
getMessage(): ?string | ?LegacyObject;

/**
* Gets the sound string from the `aps` object
Expand All @@ -139,8 +138,7 @@ export interface PushNotification {
/**
* Gets the notification's main message from the `aps` object
*/
// $FlowFixMe[unclear-type]
getAlert(): ?string | ?Object;
getAlert(): ?string | ?LegacyObject;

/**
* Gets the content-available number from the `aps` object
Expand All @@ -155,8 +153,7 @@ export interface PushNotification {
/**
* Gets the data object on the notif
*/
// $FlowFixMe[unclear-type]
getData(): ?Object;
getData(): ?LegacyObject;

/**
* Gets the thread ID on the notif
Expand Down Expand Up @@ -550,8 +547,7 @@ class PushNotificationIOS {
* `getInitialNotification` is sufficient.
*
*/
// $FlowFixMe[unclear-type]
constructor(nativeNotif: Object) {
constructor(nativeNotif: LegacyObject) {
this._data = {};
this._remoteNotificationCompleteCallbackCalled = false;
this._isRemote = nativeNotif.remote;
Expand Down Expand Up @@ -615,8 +611,7 @@ class PushNotificationIOS {
/**
* An alias for `getAlert` to get the notification's main message string.
*/
// $FlowFixMe[unclear-type]
getMessage(): ?string | ?Object {
getMessage(): ?string | ?LegacyObject {
// alias because "alert" is an ambiguous name
return this._alert;
}
Expand Down Expand Up @@ -646,8 +641,7 @@ class PushNotificationIOS {
*
* See https://reactnative.dev/docs/pushnotificationios#getalert
*/
// $FlowFixMe[unclear-type]
getAlert(): ?string | ?Object {
getAlert(): ?string | ?LegacyObject {
return this._alert;
}

Expand All @@ -674,8 +668,7 @@ class PushNotificationIOS {
*
* See https://reactnative.dev/docs/pushnotificationios#getdata
*/
// $FlowFixMe[unclear-type]
getData(): ?Object {
getData(): ?LegacyObject {
return this._data;
}

Expand Down
3 changes: 1 addition & 2 deletions packages/react-native/Libraries/Types/CodegenTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ export type DirectEventHandler<
export type Double = number;
export type Float = number;
export type Int32 = number;
/* $FlowFixMe[unclear-type] Object is forbidden in strict mode */
export type UnsafeObject = Object;
export type UnsafeObject = LegacyObject;
export type UnsafeMixed = unknown;

type DefaultTypes = number | boolean | string | ReadonlyArray<string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
* @format
*/

// $FlowFixMe[unclear-type] unclear type of events
type UnsafeEventObject = Object;
type UnsafeEventObject = LegacyObject;

export interface EventSubscription {
remove(): void;
Expand Down Expand Up @@ -78,8 +77,7 @@ export default class EventEmitter<
TEventToArgsMap extends Readonly<
Record<string, ReadonlyArray<UnsafeEventObject>>,
> = Readonly<Record<string, ReadonlyArray<UnsafeEventObject>>>,
> implements IEventEmitter<TEventToArgsMap>
{
> implements IEventEmitter<TEventToArgsMap> {
#registry: Registry<TEventToArgsMap>;

constructor() {
Expand Down
13 changes: 13 additions & 0 deletions packages/react-native/flow/LegacyObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* 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
* @format
*/

// The legacy Flow `Object` type, which is `any`. The generated TypeScript API
// (scripts/js-api/build-types) translates this type to `Object`.
declare type LegacyObject = any;
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ export type ExceptionData = {
stack: Array<StackFrame>,
id: number,
isFatal: boolean,
// flowlint-next-line unclear-type:off
extraData?: Object,
extraData?: LegacyObject,
...
};
export interface Spec extends TurboModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboMod
export interface Spec extends TurboModule {
readonly fetchSegment: (
segmentId: number,
options: Object, // flowlint-line unclear-type: off
callback: (error: ?Object) => void, // flowlint-line unclear-type: off
options: LegacyObject,
callback: (error: ?LegacyObject) => void,
) => void;
readonly getSegment?: (
segmentId: number,
options: Object, // flowlint-line unclear-type: off
callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off
options: LegacyObject,
callback: (error: ?LegacyObject, path: ?string) => void,
) => void;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* 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
*/

const replaceLegacyObjectWithObject = require('../replaceLegacyObjectWithObject');
const {parse, print} = require('flow-transform');

const prettierOptions = {parser: 'babel'};

async function translate(code: string): Promise<string> {
const parsed = await parse(code);
const result = await replaceLegacyObjectWithObject(parsed);
return print(result.ast, result.mutatedCode, prettierOptions);
}

describe('replaceLegacyObjectWithObject', () => {
test('should replace LegacyObject with Object in return annotation', async () => {
const code = `function foo(): LegacyObject {}`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"function foo(): Object {}
"
`);
});

test('should replace LegacyObject with Object in nullable union', async () => {
const code = `let foo: ?string | ?LegacyObject;`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"let foo: ?string | ?Object;
"
`);
});

test('should replace LegacyObject with Object in type alias', async () => {
const code = `type Foo = LegacyObject;`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"type Foo = Object;
"
`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* 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
*/

import type {TransformVisitor} from 'flow-transform';
import type {ParseResult} from 'flow-transform/dist/transform/parse';
import type {TransformASTResult} from 'flow-transform/dist/transform/transformAST';

const {transformAST} = require('flow-transform/dist/transform/transformAST');

const visitors: TransformVisitor = context => ({
GenericTypeAnnotation(node): void {
if (node.id.name === 'LegacyObject') {
// $FlowExpectedError[incompatible-type] - replaceNode doesn't accept a GenericTypeAnnotation object literal
context.replaceNode(node, {
type: 'GenericTypeAnnotation',
id: {
type: 'Identifier',
name: 'Object',
optional: false,
},
});
}
},
});

/**
* Replaces all LegacyObject type references with Object. LegacyObject is
* `any` in Flow, but should keep the `Object` type in the TypeScript API.
*/
async function replaceLegacyObjectWithObject(
source: ParseResult,
): Promise<TransformASTResult> {
return transformAST(source, visitors);
}

module.exports = replaceLegacyObjectWithObject;
1 change: 1 addition & 0 deletions scripts/js-api/build-types/translateSourceFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const preTransforms: Array<PreTransformFn> = [
require('./transforms/flow/replaceRequiresWithImports'),
require('./transforms/flow/replaceEmptyWithNever'),
require('./transforms/flow/replaceStringishWithString'),
require('./transforms/flow/replaceLegacyObjectWithObject'),
require('./transforms/flow/replaceNullablePropertiesWithUndefined'),
require('./transforms/flow/reattachDocComments'),
require('./transforms/flow/ensureNoUnprefixedProps'),
Expand Down
Loading