Skip to content

Commit d8a96dd

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Make remaining Utilities modules Flow strict-local (#57739)
Summary: Pull Request resolved: #57739 Upgrade `deepDiffer`, `codegenNativeCommands`, `Dimensions`, and `ReactNativeTestTools` from `flow` to `flow strict-local`, preserving public type signatures. These operate on values of arbitrary shape, so the unavoidable internal `any` usages are marked with scoped `$FlowFixMe[unclear-type]`. Changelog: [Internal] Reviewed By: javache Differential Revision: D113763789
1 parent 1cc41b2 commit d8a96dd

7 files changed

Lines changed: 73 additions & 34 deletions

File tree

packages/react-native/Libraries/Utilities/Dimensions.js

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
7+
* @flow strict-local
88
* @format
99
*/
1010

@@ -21,14 +21,39 @@ import invariant from 'invariant';
2121

2222
export type {DimensionsPayload, DisplayMetrics, DisplayMetricsAndroid};
2323

24+
export type DimensionsChangePayload = Readonly<{
25+
window: DisplayMetrics,
26+
screen: DisplayMetrics,
27+
}>;
28+
2429
/** @deprecated Use DisplayMetrics */
2530
export type ScaledSize = DisplayMetrics;
2631

2732
const eventEmitter = new EventEmitter<{
28-
change: [DimensionsPayload],
33+
change: [DimensionsChangePayload],
2934
}>();
3035
let dimensionsInitialized = false;
31-
let dimensions: DimensionsPayload;
36+
let dimensions: DimensionsChangePayload;
37+
38+
declare function addDimensionsEventListener(
39+
type: 'change',
40+
handler: (dimensions: DimensionsChangePayload) => void,
41+
): EventSubscription;
42+
declare function addDimensionsEventListener(
43+
type: 'change',
44+
handler: (dimensions: {window: {width: number, height: number}}) => void,
45+
): EventSubscription;
46+
function addDimensionsEventListener(
47+
type: 'change',
48+
handler: (dimensions: DimensionsChangePayload) => void,
49+
) {
50+
invariant(
51+
type === 'change',
52+
'Trying to subscribe to unknown event: "%s"',
53+
type,
54+
);
55+
return eventEmitter.addListener(type, handler);
56+
}
3257

3358
/**
3459
* Provides the application window's width and height. Prefer
@@ -91,6 +116,9 @@ class Dimensions {
91116
screen = window;
92117
}
93118

119+
invariant(window != null, 'Dimensions must define window metrics');
120+
invariant(screen != null, 'Dimensions must define screen metrics');
121+
94122
dimensions = {window, screen};
95123
if (dimensionsInitialized) {
96124
// Don't fire 'change' the first time the dimensions are set.
@@ -109,17 +137,8 @@ class Dimensions {
109137
* `screen` properties whose values are the same as the return values of
110138
* `Dimensions.get('window')` and `Dimensions.get('screen')`, respectively.
111139
*/
112-
static addEventListener(
113-
type: 'change',
114-
handler: Function,
115-
): EventSubscription {
116-
invariant(
117-
type === 'change',
118-
'Trying to subscribe to unknown event: "%s"',
119-
type,
120-
);
121-
return eventEmitter.addListener(type, handler);
122-
}
140+
static addEventListener: typeof addDimensionsEventListener =
141+
addDimensionsEventListener;
123142
}
124143

125144
// Subscribe before calling getConstants to make sure we don't miss any updates in between.

packages/react-native/Libraries/Utilities/ReactNativeTestTools.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
7+
* @flow strict-local
88
* @format
99
*/
1010

@@ -163,7 +163,9 @@ function maximumDepthOfJSON(node: ?ReactTestRendererJSON): number {
163163
}
164164
}
165165

166-
function renderAndEnforceStrictMode(element: React.Node): any {
166+
function renderAndEnforceStrictMode(
167+
element: React.Node,
168+
): ReactTestRendererType {
167169
expectNoConsoleError();
168170
return renderWithStrictMode(element);
169171
}
@@ -217,8 +219,13 @@ function scrollToBottom(instance: ReactTestInstance) {
217219
// To make error messages a little bit better, we attach a custom toString
218220
// implementation to a predicate
219221
function withMessage(fn: Predicate, message: string): Predicate {
220-
(fn as any).toString = () => message;
221-
return fn;
222+
return new Proxy(fn, {
223+
get(target, property, receiver) {
224+
return property === 'toString'
225+
? () => message
226+
: Reflect.get(target, property, receiver);
227+
},
228+
});
222229
}
223230

224231
export {byClickable};

packages/react-native/Libraries/Utilities/codegenNativeCommands.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,40 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
7+
* @flow strict-local
88
* @format
99
*/
1010

11+
import type {HostInstance} from '../../src/private/types/HostInstance';
12+
1113
const {dispatchCommand} = require('../ReactNative/RendererProxy');
1214

1315
type NativeCommandsOptions<T = string> = Readonly<{
1416
supportedCommands: ReadonlyArray<T>,
1517
}>;
1618

19+
declare function castCommandObject<T extends interface {}>(commandObj: {
20+
[keyof T]: (...ReadonlyArray<unknown>) => void,
21+
}): T;
22+
function castCommandObject(commandObj: interface {}) {
23+
return commandObj;
24+
}
25+
1726
function codegenNativeCommands<T extends interface {}>(
18-
options: NativeCommandsOptions<keyof T>,
27+
options: NativeCommandsOptions<keyof T & string>,
1928
): T {
2029
const commandObj: {[keyof T]: (...ReadonlyArray<unknown>) => void} = {};
2130

2231
options.supportedCommands.forEach(command => {
23-
// $FlowFixMe[missing-local-annot]
24-
commandObj[command] = (ref, ...args) => {
25-
// $FlowFixMe[incompatible-type]
32+
commandObj[command] = (
33+
ref: HostInstance,
34+
...args: Array<unknown>
35+
): void => {
2636
dispatchCommand(ref, command, args);
2737
};
2838
});
2939

30-
return commandObj as any as T;
40+
return castCommandObject(commandObj);
3141
}
3242

3343
export default codegenNativeCommands;

packages/react-native/Libraries/Utilities/differ/__tests__/deepDiffer-itest.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ describe('deepDiffer', function () {
136136
expect(
137137
deepDiffer(
138138
() => {},
139-
x => x,
139+
(x: unknown) => x,
140140
),
141141
).toBe(false);
142142
const f = () => {};
@@ -146,7 +146,7 @@ describe('deepDiffer', function () {
146146
expect(
147147
deepDiffer(
148148
() => {},
149-
x => x,
149+
(x: unknown) => x,
150150
undefined,
151151
{unsafelyIgnoreFunctions: false},
152152
),
@@ -160,7 +160,7 @@ describe('deepDiffer', function () {
160160
expect(
161161
deepDiffer(
162162
() => {},
163-
x => x,
163+
(x: unknown) => x,
164164
{unsafelyIgnoreFunctions: false},
165165
),
166166
).toBe(true);

packages/react-native/Libraries/Utilities/differ/deepDiffer.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
7+
* @flow strict-local
88
* @format
99
*/
1010

@@ -29,8 +29,8 @@ function unstable_setLogListeners(listeners: ?LogListeners) {
2929
* @returns {bool} true if different, false if equal
3030
*/
3131
function deepDiffer(
32-
one: any,
33-
two: any,
32+
one: unknown,
33+
two: unknown,
3434
maxDepthOrOptions: Options | number = -1,
3535
maybeOptions?: Options,
3636
): boolean {
@@ -73,7 +73,9 @@ function deepDiffer(
7373
return true;
7474
}
7575
if (Array.isArray(one)) {
76-
// We know two is also an array because the constructors are equal
76+
if (!Array.isArray(two)) {
77+
return true;
78+
}
7779
const len = one.length;
7880
if (two.length !== len) {
7981
return true;

packages/react-native/Libraries/Utilities/useWindowDimensions.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ export default function useWindowDimensions():
2727
useEffect(() => {
2828
function handleChange({
2929
window,
30-
}: {
30+
}: Readonly<{
3131
window: DisplayMetrics | DisplayMetricsAndroid,
32-
}) {
32+
...
33+
}>) {
3334
if (
3435
dimensions.width !== window.width ||
3536
dimensions.height !== window.height ||

packages/rn-tester/js/examples/Dimensions/DimensionsExample.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import * as React from 'react';
1515
import {useEffect, useState} from 'react';
1616
import {Button, Dimensions, View, useWindowDimensions} from 'react-native';
1717

18-
type Props = {dim: string};
18+
type Props = {dim: 'screen' | 'window'};
1919

2020
function DimensionsSubscription(props: Props) {
2121
const [dims, setDims] = useState(() => Dimensions.get(props.dim));

0 commit comments

Comments
 (0)