From 2ebbf8b1a2393def55768fb87f0da880f96c9825 Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Sat, 22 Feb 2025 06:23:40 -0800 Subject: [PATCH] [flow] Ban more kinds of usages of React dollar types Summary: It's starting locking down on these types, so that we can remove it in the next next release. Changelog: [errors] Use of `React$ComponentType`, `React$Context` and `React$RefSetter` will now trigger `internal-type` errors. Reviewed By: gkz Differential Revision: D70014990 fbshipit-source-id: 4e73ce37154b6080a181087ee319a93d0f874e36 --- src/typing/type_annotation.ml | 33 ++++++ .../badly_positioned_unknown_use.exp | 2 +- tests/badly_positioned_unknown_use/test1.js | 4 +- .../ub_order_regression.js | 2 +- tests/more_react/react-copy-write.js | 4 +- .../opaque.js | 2 +- ...types_and_component_syntax_destructors.exp | 2 +- tests/react/contravariant_refsetter.js | 4 +- tests/react/creatRef.js | 2 +- tests/react/hoc.js | 6 +- tests/react/react.exp | 103 ++++++------------ tests/react/useContext_hook.js | 4 +- tests/react/use_hook.js | 2 +- tests/spread/error_positions.js | 2 +- tests/spread/spread.exp | 4 +- 15 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/typing/type_annotation.ml b/src/typing/type_annotation.ml index 35bfa1ea3ab..9faf1bb22d5 100644 --- a/src/typing/type_annotation.ml +++ b/src/typing/type_annotation.ml @@ -1371,6 +1371,28 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct ) ); local_generic_type () + | "React$ComponentType" -> + if not (Context.is_lib_file cx) then + Flow_js_utils.add_output + cx + (Error_message.EInternalType + ( loc, + Flow_intermediate_error_types.ReactDollarUtilityTypesWithNonDollarAliases + "ComponentType" + ) + ); + local_generic_type () + | "React$Context" -> + if not (Context.is_lib_file cx) then + Flow_js_utils.add_output + cx + (Error_message.EInternalType + ( loc, + Flow_intermediate_error_types.ReactDollarUtilityTypesWithNonDollarAliases + "Context" + ) + ); + local_generic_type () | "React$ElementRef" -> if not (Context.is_lib_file cx) then Flow_js_utils.add_output @@ -1382,6 +1404,17 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct ) ); local_generic_type () + | "React$RefSetter" -> + if not (Context.is_lib_file cx) then + Flow_js_utils.add_output + cx + (Error_message.EInternalType + ( loc, + Flow_intermediate_error_types.ReactDollarUtilityTypesWithNonDollarAliases + "RefSetter" + ) + ); + local_generic_type () (* other applications with id as head expr *) | _ -> local_generic_type () end diff --git a/tests/badly_positioned_unknown_use/badly_positioned_unknown_use.exp b/tests/badly_positioned_unknown_use/badly_positioned_unknown_use.exp index 0ee50bb68c8..abfcafe8308 100644 --- a/tests/badly_positioned_unknown_use/badly_positioned_unknown_use.exp +++ b/tests/badly_positioned_unknown_use/badly_positioned_unknown_use.exp @@ -11,7 +11,7 @@ References: 20| var x = f, _>()(foo(Comp)); ^^ [1] test1.js:4:34 - 4| Component: React$ComponentType<{|...P|}>, + 4| Component: React.ComponentType<{|...P|}>, ^^^^^^^^ [2] diff --git a/tests/badly_positioned_unknown_use/test1.js b/tests/badly_positioned_unknown_use/test1.js index d8e8c2560af..b3bf505e222 100644 --- a/tests/badly_positioned_unknown_use/test1.js +++ b/tests/badly_positioned_unknown_use/test1.js @@ -1,8 +1,8 @@ import * as React from 'react'; declare export function foo

( - Component: React$ComponentType<{|...P|}>, -): React$ComponentType

; + Component: React.ComponentType<{|...P|}>, +): React.ComponentType

; class Comp extends React.Component<{}, {}> {} diff --git a/tests/implicit_instantiation/ub_order_regression.js b/tests/implicit_instantiation/ub_order_regression.js index ea81ed54c4c..d8d0f82f463 100644 --- a/tests/implicit_instantiation/ub_order_regression.js +++ b/tests/implicit_instantiation/ub_order_regression.js @@ -4,7 +4,7 @@ import * as React from 'react'; declare var Comp: (props: {}) => $FlowFixMe; class C {} declare var withStore: ( - C: React$ComponentType, + C: React.ComponentType, ) => C<$Diff>; withStore(Comp) as C<{}>; // okay diff --git a/tests/more_react/react-copy-write.js b/tests/more_react/react-copy-write.js index 908c0925f70..48668e4e857 100644 --- a/tests/more_react/react-copy-write.js +++ b/tests/more_react/react-copy-write.js @@ -1,6 +1,8 @@ //@flow var React = require("react"); +import type {ComponentType} from 'react'; + export type Recipe = (draft: T, state: $ReadOnly) => void; export type Mutate = (recipe: Recipe) => void; @@ -11,7 +13,7 @@ type ProviderProps = {| initialState?: T, |}; -export type Provider = React$ComponentType>; +export type Provider = ComponentType>; type GetReturnType = ((T) => S) => S; diff --git a/tests/opaque_types_and_component_syntax_destructors/opaque.js b/tests/opaque_types_and_component_syntax_destructors/opaque.js index 255d2e41081..d0cfa6e7f9f 100644 --- a/tests/opaque_types_and_component_syntax_destructors/opaque.js +++ b/tests/opaque_types_and_component_syntax_destructors/opaque.js @@ -2,7 +2,7 @@ import {createContext, useContext} from 'react' export opaque type Tag = number; -export const Context: React$Context = createContext(3); +export const Context: React.Context = createContext(3); component Foo() { const context = useContext(Context); diff --git a/tests/opaque_types_and_component_syntax_destructors/opaque_types_and_component_syntax_destructors.exp b/tests/opaque_types_and_component_syntax_destructors/opaque_types_and_component_syntax_destructors.exp index 61f6258eca9..5640fef2782 100644 --- a/tests/opaque_types_and_component_syntax_destructors/opaque_types_and_component_syntax_destructors.exp +++ b/tests/opaque_types_and_component_syntax_destructors/opaque_types_and_component_syntax_destructors.exp @@ -8,7 +8,7 @@ Cannot cast `context` to number because `Tag` [1] is incompatible with number [2 References: opaque.js:5:37 - 5| export const Context: React$Context = createContext(3); + 5| export const Context: React.Context = createContext(3); ^^^ [1] non-local.js:7:14 7| context as number; // ERROR diff --git a/tests/react/contravariant_refsetter.js b/tests/react/contravariant_refsetter.js index c3ecb7719db..880580a78a6 100644 --- a/tests/react/contravariant_refsetter.js +++ b/tests/react/contravariant_refsetter.js @@ -2,11 +2,9 @@ import * as React from 'react'; declare const x: React.RefSetter; (x: React.RefSetter); // OK! -(x: React$RefSetter); // OK! -declare const y: React$RefSetter; +declare const y: React.RefSetter; (y: React.RefSetter); // OK! -(y: React$RefSetter); // OK! (x: React.RefSetter); // ERROR (y: React.RefSetter); // ERROR diff --git a/tests/react/creatRef.js b/tests/react/creatRef.js index 8ce8cc3efff..e14621ca1cd 100644 --- a/tests/react/creatRef.js +++ b/tests/react/creatRef.js @@ -3,7 +3,7 @@ import React from 'react'; { class MyComponent extends React.Component {} - const ref: {current: null | React$ComponentType} = React.createRef(); // Ok + const ref: {current: null | React.ComponentType} = React.createRef(); // Ok } { diff --git a/tests/react/hoc.js b/tests/react/hoc.js index 0738c3e0bff..3507fdd6ec4 100644 --- a/tests/react/hoc.js +++ b/tests/react/hoc.js @@ -1,8 +1,8 @@ import * as React from 'react'; function myHOC( - Component: React$ComponentType<{foo: number, bar: number}>, -): React$ComponentType<{foo: number}> { + Component: React.ComponentType<{foo: number, bar: number}>, +): React.ComponentType<{foo: number}> { return class extends React.Component<{foo: number}, {bar: number}> { state: {bar: number} = {bar: 2}; render(): React.Node { @@ -33,7 +33,7 @@ function UnwrappedFun(props: {foo: number, bar: number}) { myHOC(class Empty extends React.Component<{foo: string}, void> {}); // Error myHOC(function Empty(props: {foo: string}) {}); // Error -const Wrapped: React$ComponentType<{foo: number}> = myHOC(Unwrapped); +const Wrapped: React.ComponentType<{foo: number}> = myHOC(Unwrapped); const WrappedFun = myHOC(UnwrappedFun); ; // Error: `foo` is required. diff --git a/tests/react/react.exp b/tests/react/react.exp index feabf357844..67408d357ec 100644 --- a/tests/react/react.exp +++ b/tests/react/react.exp @@ -1,19 +1,19 @@ -Error ---------------------------------------------------------------------------------- contravariant_refsetter.js:11:2 +Error ----------------------------------------------------------------------------------- contravariant_refsetter.js:9:2 Cannot cast `x` to `React.RefSetter` because in type argument `T` [1]: [incompatible-cast] - Either boolean [2] is incompatible with number [3]. - Or boolean [2] is incompatible with string [4]. - contravariant_refsetter.js:11:2 - 11| (x: React.RefSetter); // ERROR + contravariant_refsetter.js:9:2 + 9| (x: React.RefSetter); // ERROR ^ References: /react.js:357:34 357| declare export type RefSetter<-T> = React$RefSetter; ^ [1] - contravariant_refsetter.js:11:39 - 11| (x: React.RefSetter); // ERROR + contravariant_refsetter.js:9:39 + 9| (x: React.RefSetter); // ERROR ^^^^^^^ [2] contravariant_refsetter.js:3:34 3| declare const x: React.RefSetter; @@ -23,62 +23,29 @@ References: ^^^^^^ [4] -Error ---------------------------------------------------------------------------------- contravariant_refsetter.js:12:2 +Error ---------------------------------------------------------------------------------- contravariant_refsetter.js:10:2 -Cannot cast `y` to `React.RefSetter` because: [incompatible-cast] - - Either boolean [1] is incompatible with number [2] in the first parameter. - - Or boolean [1] is incompatible with string [3] in the first parameter. - - Or function type [4] is incompatible with object type [5]. Functions without statics are not compatible with objects. - - contravariant_refsetter.js:12:2 - 12| (y: React.RefSetter); // ERROR - ^ - -References: - contravariant_refsetter.js:12:39 - 12| (y: React.RefSetter); // ERROR - ^^^^^^^ [1] - contravariant_refsetter.js:7:34 - 7| declare const y: React$RefSetter; - ^^^^^^ [2] - contravariant_refsetter.js:7:43 - 7| declare const y: React$RefSetter; - ^^^^^^ [3] - contravariant_refsetter.js:7:18 - 7| declare const y: React$RefSetter; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [4] - /react.js:192:5 - 192| | { -current: T | null, ... } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ [5] - - -Error ---------------------------------------------------------------------------------- contravariant_refsetter.js:12:2 - -Cannot cast `y` to `React.RefSetter` because: [incompatible-cast] - - Either boolean [1] is incompatible with number [2] in property `current`. - - Or boolean [1] is incompatible with string [3] in property `current`. - - Or object type [4] is incompatible with function type [5]. Non-callable objects are not compatible with functions. +Cannot cast `y` to `React.RefSetter` because in type argument `T` [1]: [incompatible-cast] + - Either boolean [2] is incompatible with number [3]. + - Or boolean [2] is incompatible with string [4]. - contravariant_refsetter.js:12:2 - 12| (y: React.RefSetter); // ERROR + contravariant_refsetter.js:10:2 + 10| (y: React.RefSetter); // ERROR ^ References: - contravariant_refsetter.js:12:39 - 12| (y: React.RefSetter); // ERROR - ^^^^^^^ [1] - contravariant_refsetter.js:7:34 - 7| declare const y: React$RefSetter; - ^^^^^^ [2] - contravariant_refsetter.js:7:43 - 7| declare const y: React$RefSetter; - ^^^^^^ [3] - contravariant_refsetter.js:7:18 - 7| declare const y: React$RefSetter; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [4] - /react.js:193:6 - 193| | ((T | null) => mixed) - ^^^^^^^^^^^^^^^^^^^ [5] + /react.js:357:34 + 357| declare export type RefSetter<-T> = React$RefSetter; + ^ [1] + contravariant_refsetter.js:10:39 + 10| (y: React.RefSetter); // ERROR + ^^^^^^^ [2] + contravariant_refsetter.js:6:34 + 6| declare const y: React.RefSetter; + ^^^^^^ [3] + contravariant_refsetter.js:6:43 + 6| declare const y: React.RefSetter; + ^^^^^^ [4] Error ------------------------------------------------------------------------------------------- createContext.js:16:24 @@ -575,7 +542,7 @@ References: 9| ; // Error: `foo` is required. ^^^^^^^^^^^^^ [1] hoc.js:4:34 - 4| Component: React$ComponentType<{foo: number, bar: number}>, + 4| Component: React.ComponentType<{foo: number, bar: number}>, ^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] @@ -593,7 +560,7 @@ References: 9| ; // Error: `foo` is required. ^^^^^^^^^^^^^ [1] hoc.js:4:34 - 4| Component: React$ComponentType<{foo: number, bar: number}>, + 4| Component: React.ComponentType<{foo: number, bar: number}>, ^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] @@ -611,7 +578,7 @@ References: 10| ; // Error: `bar` is required. ^^^^^^^^^^^^^^^^^^^^^^ [1] hoc.js:4:34 - 4| Component: React$ComponentType<{foo: number, bar: number}>, + 4| Component: React.ComponentType<{foo: number, bar: number}>, ^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] @@ -626,7 +593,7 @@ property `foo`. [incompatible-call] References: hoc.js:4:40 - 4| Component: React$ComponentType<{foo: number, bar: number}>, + 4| Component: React.ComponentType<{foo: number, bar: number}>, ^^^^^^ [2] @@ -641,7 +608,7 @@ Cannot call `myHOC` with function bound to `Component` because number [1] is inc References: hoc.js:4:40 - 4| Component: React$ComponentType<{foo: number, bar: number}>, + 4| Component: React.ComponentType<{foo: number, bar: number}>, ^^^^^^ [1] hoc.js:34:35 34| myHOC(function Empty(props: {foo: string}) {}); // Error @@ -662,7 +629,7 @@ References: 39| ; // Error: `foo` is required. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] hoc.js:36:36 - 36| const Wrapped: React$ComponentType<{foo: number}> = myHOC(Unwrapped); + 36| const Wrapped: React.ComponentType<{foo: number}> = myHOC(Unwrapped); ^^^^^^^^^^^^^ [2] @@ -680,7 +647,7 @@ References: 41| ; // Error: `foo` is required. ^^^^^^^^^^^^^^ [1] hoc.js:5:24 - 5| ): React$ComponentType<{foo: number}> { + 5| ): React.ComponentType<{foo: number}> { ^^^^^^^^^^^^^ [2] @@ -1655,12 +1622,12 @@ Cannot call `React.createContext` with `'hello'` bound to `defaultValue` because `CustomType` [2]. [incompatible-call] useContext_hook.js:21:73 - 21| const InvalidContext: React$Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType + 21| const InvalidContext: React.Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType ^^^^^^^ [1] References: useContext_hook.js:21:39 - 21| const InvalidContext: React$Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType + 21| const InvalidContext: React.Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType ^^^^^^^^^^ [2] @@ -1675,7 +1642,7 @@ Cannot assign `React.useContext(...)` to `stringValue` because `CustomType` [1] References: useContext_hook.js:23:38 - 23| const CustomContext: React$Context = React.createContext({ + 23| const CustomContext: React.Context = React.createContext({ ^^^^^^^^^^ [1] useContext_hook.js:13:20 13| let stringValue: string; @@ -2422,7 +2389,7 @@ Cannot assign `use(...)` to `notAny` because `Theme` [1] is incompatible with nu References: use_hook.js:4:43 - 4| declare const ThemeContext: React$Context; + 4| declare const ThemeContext: React.Context; ^^^^^ [1] use_hook.js:19:17 19| const notAny: 0 = use(ThemeContext); @@ -2543,7 +2510,7 @@ References: -Found 145 errors +Found 144 errors Only showing the most relevant union/intersection branches. To see all branches, re-run Flow with --show-all-branches diff --git a/tests/react/useContext_hook.js b/tests/react/useContext_hook.js index dfe9c973c53..538e89539bb 100644 --- a/tests/react/useContext_hook.js +++ b/tests/react/useContext_hook.js @@ -18,9 +18,9 @@ type CustomType = {| stringValue = React.useContext(StringContext); // Ok numericValue = React.useContext(StringContext); // Error: string is incompatible with number - const InvalidContext: React$Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType + const InvalidContext: React.Context = React.createContext('hello'); // Error: inexact string is incompatible with exact CustomType - const CustomContext: React$Context = React.createContext({ + const CustomContext: React.Context = React.createContext({ foo: 'abc', bar: 123, }); diff --git a/tests/react/use_hook.js b/tests/react/use_hook.js index b8c2d31ed53..52f2a5e728f 100644 --- a/tests/react/use_hook.js +++ b/tests/react/use_hook.js @@ -1,7 +1,7 @@ import {use} from 'react'; declare opaque type Theme; -declare const ThemeContext: React$Context; +declare const ThemeContext: React.Context; declare const AnswerPromise: Promise<42>; diff --git a/tests/spread/error_positions.js b/tests/spread/error_positions.js index 7452842a7d4..5229dcbbc3f 100644 --- a/tests/spread/error_positions.js +++ b/tests/spread/error_positions.js @@ -4,7 +4,7 @@ type F = (React.ElementConfig => void) => void // error should not appear declare function foo(T): (React.ElementConfig => void) => void -declare function bar

(React$ComponentType<{ m: number, ...P}>): React$ComponentType

; +declare function bar

(React.ComponentType<{ m: number, ...P}>): React.ComponentType

; class C extends React.Component<{}> {} diff --git a/tests/spread/spread.exp b/tests/spread/spread.exp index 188764a7bc5..4b00976c5dc 100644 --- a/tests/spread/spread.exp +++ b/tests/spread/spread.exp @@ -33,7 +33,7 @@ contain `m` with a type that conflicts with `m`'s definition in object type [1]. References: error_positions.js:7:45 - 7| declare function bar

(React$ComponentType<{ m: number, ...P}>): React$ComponentType

; + 7| declare function bar

(React.ComponentType<{ m: number, ...P}>): React.ComponentType

; ^^^^^^^^^^^^^^^^^^ [1] error_positions.js:9:33 9| class C extends React.Component<{}> {} @@ -51,7 +51,7 @@ class `C` [2]. [incompatible-call] References: error_positions.js:7:67 - 7| declare function bar

(React$ComponentType<{ m: number, ...P}>): React$ComponentType

; + 7| declare function bar

(React.ComponentType<{ m: number, ...P}>): React.ComponentType

; ^^^^^^^^^^^^^^^^^^^^^^ [1] error_positions.js:11:17 11| (foo(bar(C)): F); // error on call