From 000b9b042932e7f33aecc52a0f4bcbc3cc879e97 Mon Sep 17 00:00:00 2001 From: Oleg Nechiporenko Date: Fri, 21 Dec 2018 21:59:23 +0300 Subject: [PATCH 1/4] Concise typings for nanoevents (#3022) * Concise typings for nanoevents * nanoevents: tests update --- .../flow_v0.50.x-/nanoevents_v1.0.x.js | 8 +- .../test_nanoevents_v1.0.x.js | 77 ++++++++++++++----- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/definitions/npm/nanoevents_v1.0.x/flow_v0.50.x-/nanoevents_v1.0.x.js b/definitions/npm/nanoevents_v1.0.x/flow_v0.50.x-/nanoevents_v1.0.x.js index edb97aad34..ca997e2800 100644 --- a/definitions/npm/nanoevents_v1.0.x/flow_v0.50.x-/nanoevents_v1.0.x.js +++ b/definitions/npm/nanoevents_v1.0.x/flow_v0.50.x-/nanoevents_v1.0.x.js @@ -1,9 +1,9 @@ declare module "nanoevents" { - declare export default class NanoEvents { - constructor(): NanoEvents, + declare export default class NanoEvents { + constructor(): NanoEvents, - on(event: string, cb: (any) => void): void, + on>(event: K, cb: ($ElementType) => void): void, - emit(event: string, data?: any): void + emit>(event: K, data?: $ElementType): void } } diff --git a/definitions/npm/nanoevents_v1.0.x/test_nanoevents_v1.0.x.js b/definitions/npm/nanoevents_v1.0.x/test_nanoevents_v1.0.x.js index 8effc245b4..c685181f14 100644 --- a/definitions/npm/nanoevents_v1.0.x/test_nanoevents_v1.0.x.js +++ b/definitions/npm/nanoevents_v1.0.x/test_nanoevents_v1.0.x.js @@ -1,31 +1,68 @@ +import { describe, it } from "flow-typed-test"; import NanoEvents from "nanoevents"; -// $ExpectError: call a constructor -NanoEvents(); +describe("default", () => { + it("should create instance", () => { + // $ExpectError: call a constructor + NanoEvents(); -// $ExpectError: not accept arguments -new NanoEvents(1); + // $ExpectError: not accept arguments + new NanoEvents(1); -const emitter = new NanoEvents(); + const emitter = new NanoEvents(); -emitter.emit("event"); + emitter.emit("message"); -// $ExpectError: allow only string as event name -emitter.emit(1); + // $ExpectError: allow only string as event name + emitter.emit(1); -emitter.emit("event", {}); -emitter.emit("event", 1); -emitter.emit("event", ""); -emitter.emit("event", true); + emitter.emit("event", {}); + emitter.emit("event", 1); + emitter.emit("event", ""); + emitter.emit("event", true); -emitter.on("event", () => {}); + emitter.on("event", () => {}); -emitter.on("event", arg => { - console.log(arg); -}); + emitter.on("event", arg => { + console.log(arg); + }); + + // $ExpectError: allow only string as even name + emitter.on(1, () => {}); + + // $ExpectError: allow only functions as callback + emitter.on("event", 1); + }); + + it('should throw error on emit wrong type', () => { + const emitter = new NanoEvents<{ message: 'message-1' | 'message-2', error: Error }>(); + + // $ExpectError: allow only message-1 or message-2 strings + emitter.emit('message', 1); + emitter.emit('message', 'message-1'); + emitter.emit('message', 'message-2'); -// $ExpectError: allow only string as even name -emitter.on(1, () => {}); + // $ExpectError: allow only Error + emitter.emit('error', 'error message'); + emitter.emit('error', new Error('error message')); -// $ExpectError: allow only functions as callback -emitter.on("event", 1); + // $ExpectError: allow only message or string events + emitter.emit('wrong event'); + }); + + it('should throw error on handle wrong event type or wrong handler type', () => { + const emitter = new NanoEvents<{ message: 'message-1' | 'message-2', error: Error }>(); + + emitter.on('message', message => { + // $ExpectError: allow only message-1 or message-2 strings + (message: 'wrong message'); + (message: 'message-1' | 'message-2'); + }); + + emitter.on('error', error => { + // $ExpectError: allow only Error instance + (error: string); + (error: Error); + }) + }); +}); From e64da7782d8cf648feb301cdfe268ab7d5c80598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Dupanovi=C4=87?= Date: Sat, 22 Dec 2018 20:54:01 +0100 Subject: [PATCH 2/4] Add all webpack devtool variants (#3029) See: https://webpack.js.org/configuration/devtool/. --- .../flow_v0.71.x-/webpack_v4.x.x.js | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/definitions/npm/webpack_v4.x.x/flow_v0.71.x-/webpack_v4.x.x.js b/definitions/npm/webpack_v4.x.x/flow_v0.71.x-/webpack_v4.x.x.js index deb86271c8..1e05a02575 100644 --- a/definitions/npm/webpack_v4.x.x/flow_v0.71.x-/webpack_v4.x.x.js +++ b/definitions/npm/webpack_v4.x.x/flow_v0.71.x-/webpack_v4.x.x.js @@ -405,7 +405,48 @@ declare module 'webpack' { context?: string, dependencies?: Array, devServer?: { [k: string]: any }, - devtool?: string | false, + devtool?: + | '@cheap-eval-source-map' + | '@cheap-module-eval-source-map' + | '@cheap-module-source-map' + | '@cheap-source-map' + | '@eval-source-map' + | '@eval' + | '@hidden-source-map' + | '@inline-source-map' + | '@nosources-source-map' + | '@source-map' + | '#@cheap-eval-source-map' + | '#@cheap-module-eval-source-map' + | '#@cheap-module-source-map' + | '#@cheap-source-map' + | '#@eval-source-map' + | '#@eval' + | '#@hidden-source-map' + | '#@inline-source-map' + | '#@nosources-source-map' + | '#@source-map' + | '#cheap-eval-source-map' + | '#cheap-module-eval-source-map' + | '#cheap-module-source-map' + | '#cheap-source-map' + | '#eval-source-map' + | '#eval' + | '#hidden-source-map' + | '#inline-source-map' + | '#nosources-source-map' + | '#source-map' + | 'cheap-eval-source-map' + | 'cheap-module-eval-source-map' + | 'cheap-module-source-map' + | 'cheap-source-map' + | 'eval-source-map' + | 'eval' + | 'hidden-source-map' + | 'inline-source-map' + | 'nosources-source-map' + | 'source-map' + | false, entry?: Entry, externals?: Externals, loader?: { [k: string]: any }, From f8afc4cfdd47620559b3c0174fa61a56c0765534 Mon Sep 17 00:00:00 2001 From: Peter Leonov Date: Wed, 26 Dec 2018 13:34:54 +0100 Subject: [PATCH 3/4] [react-redux_v5.x.x] Add support for Flow 0.89+ (#3012) * limit the upper flow version * copy existing typings * replace with the new typings for flow 0.85+ * add `withRef` Unfortunately without affecting `getWrappedInstance()` * proxy static props * provide types in some cases * fix the mergeProps mistake * use spread instead of $Diff * fix exact options and the only merge argument * try with only flow 0.89+ * createProvider() should return a class * make it look nicer and add support for factory functions * add the main documentation section * fix typo * add WrappedComponent and pass Props instead of MergedProps * remove deprecated $Subtype * add the copy of test_connect but with exported everything * fix typo and name properly type argument * explained the misleading errors better for better future understanding Also moved one error suppression to match others. * fix typo * use Dispatch type directly instead of manually constructing it from Action --- .../react-redux_v5.x.x.js | 0 .../test_Provider.js | 0 .../test_connect.js | 0 .../test_connectAdvanced.js | 0 .../flow_v0.89.x-/react-redux_v5.x.x.js | 218 +++++++ .../flow_v0.89.x-/test_Provider.js | 54 ++ .../flow_v0.89.x-/test_connect.js | 551 ++++++++++++++++ .../flow_v0.89.x-/test_connectAdvanced.js | 124 ++++ .../flow_v0.89.x-/test_connectExported.js | 603 ++++++++++++++++++ 9 files changed, 1550 insertions(+) rename definitions/npm/react-redux_v5.x.x/{flow_v0.68.0- => flow_v0.68.0-v0.84.x}/react-redux_v5.x.x.js (100%) rename definitions/npm/react-redux_v5.x.x/{flow_v0.68.0- => flow_v0.68.0-v0.84.x}/test_Provider.js (100%) rename definitions/npm/react-redux_v5.x.x/{flow_v0.68.0- => flow_v0.68.0-v0.84.x}/test_connect.js (100%) rename definitions/npm/react-redux_v5.x.x/{flow_v0.68.0- => flow_v0.68.0-v0.84.x}/test_connectAdvanced.js (100%) create mode 100644 definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js create mode 100644 definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_Provider.js create mode 100644 definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js create mode 100644 definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectAdvanced.js create mode 100644 definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectExported.js diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/react-redux_v5.x.x.js b/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/react-redux_v5.x.x.js similarity index 100% rename from definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/react-redux_v5.x.x.js rename to definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/react-redux_v5.x.x.js diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_Provider.js b/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_Provider.js similarity index 100% rename from definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_Provider.js rename to definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_Provider.js diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_connect.js b/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_connect.js similarity index 100% rename from definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_connect.js rename to definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_connect.js diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_connectAdvanced.js b/definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_connectAdvanced.js similarity index 100% rename from definitions/npm/react-redux_v5.x.x/flow_v0.68.0-/test_connectAdvanced.js rename to definitions/npm/react-redux_v5.x.x/flow_v0.68.0-v0.84.x/test_connectAdvanced.js diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js new file mode 100644 index 0000000000..11a31fa528 --- /dev/null +++ b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js @@ -0,0 +1,218 @@ +/** +The order of type arguments for connect() is as follows: + +connect(…) + +In Flow v0.89 only the first two are mandatory to specify. Other 4 can be repaced with the new awesome type placeholder: + +connect(…) + +But beware, in case of weird type errors somewhere in random places +just type everything and get to a green field and only then try to +remove the definitions you see bogus. + +Decrypting the abbreviations: + WC = Component being wrapped + S = State + D = Dispatch + OP = OwnProps + SP = StateProps + DP = DispatchProps + MP = Merge props + RSP = Returned state props + RDP = Returned dispatch props + RMP = Returned merge props + CP = Props for returned component + Com = React Component + ST = Static properties of Com + EFO = Extra factory options (used only in connectAdvanced) +*/ + +declare module "react-redux" { + // ------------------------------------------------------------ + // Typings for connect() + // ------------------------------------------------------------ + + declare export type Options = {| + pure?: boolean, + withRef?: boolean, + areStatesEqual?: (next: S, prev: S) => boolean, + areOwnPropsEqual?: (next: OP, prev: OP) => boolean, + areStatePropsEqual?: (next: SP, prev: SP) => boolean, + areMergedPropsEqual?: (next: MP, prev: MP) => boolean, + storeKey?: string, + |}; + + declare type MapStateToProps<-S, -OP, +SP> = + | ((state: S, ownProps: OP) => SP) + // If you want to use the factory function but get a strange error + // like "function is not an object" then just type the factory function + // like this: + // const factory: (State, OwnProps) => (State, OwnProps) => StateProps + // and provide the StateProps type to the SP type parameter. + | ((state: S, ownProps: OP) => (state: S, ownProps: OP) => SP); + + declare type MapDispatchToPropsFn = + | ((dispatch: D, ownProps: OP) => DP) + // If you want to use the factory function but get a strange error + // like "function is not an object" then just type the factory function + // like this: + // const factory: (Dispatch, OwnProps) => (Dispatch, OwnProps) => DispatchProps + // and provide the DispatchProps type to the DP type parameter. + | ((dispatch: D, ownProps: OP) => (dispatch: D, ownProps: OP) => DP); + + declare class ConnectedComponent extends React$Component { + static +WrappedComponent: WC; + getWrappedInstance(): React$ElementRef; + } + declare type Connector = >( + WC, + ) => Class> & WC; + + // No `mergeProps` argument + + declare export function connect<-P, -OP, -SP, -DP, -S, -D>( + mapStateToProps?: null | void, + mapDispatchToProps?: null | void, + mergeProps?: null | void, + options?: ?Options, + // Got error like inexact OwnProps is incompatible with exact object type? + // Just make your OP parameter an exact object. + ): Connector; + + declare export function connect<-P, -OP, -SP, -DP, -S, -D>( + // If you get error here try adding return type to your mapStateToProps function + mapStateToProps: MapStateToProps, + mapDispatchToProps?: null | void, + mergeProps?: null | void, + options?: ?Options, + // Got error like inexact OwnProps is incompatible with exact object type? + // Just make your OP parameter an exact object. + ): Connector; + + declare export function connect<-P, -OP, -SP, -DP, S, D>( + mapStateToProps: null | void, + mapDispatchToProps: MapDispatchToPropsFn | DP, + mergeProps?: null | void, + options?: ?Options, + // Got error like inexact OwnProps is incompatible with exact object type? + // Just make your OP parameter an exact object. + ): Connector; + + declare export function connect<-P, -OP, -SP, -DP, S, D>( + // If you get error here try adding return type to your mapStateToProps function + mapStateToProps: MapStateToProps, + mapDispatchToProps: MapDispatchToPropsFn | DP, + mergeProps?: null | void, + options?: ?Options, + // Got error like inexact OwnProps is incompatible with exact object type? + // Just make your OP parameter an exact object. + ): Connector; + + // With `mergeProps` argument + + declare type MergeProps<+P, -OP, -SP, -DP> = ( + stateProps: SP, + dispatchProps: DP, + ownProps: OP, + ) => P; + + declare export function connect<-P, -OP, -S, -D, SP, DP>( + mapStateToProps: null | void, + mapDispatchToProps: null | void, + // If you get error here try adding return type to you mapStateToProps function + mergeProps: MergeProps, + options?: ?Options, + ): Connector; + + declare export function connect<-P, -OP, -S, -D, SP, DP>( + mapStateToProps: MapStateToProps, + mapDispatchToProps: null | void, + // If you get error here try adding return type to you mapStateToProps function + mergeProps: MergeProps, + options?: ?Options, + ): Connector; + + declare export function connect<-P, -OP, -S, -D, SP, DP>( + mapStateToProps: null | void, + mapDispatchToProps: MapDispatchToPropsFn | DP, + mergeProps: MergeProps, + options?: ?Options, + ): Connector; + + declare export function connect<-P, -OP, -S, -D, SP, DP>( + mapStateToProps: MapStateToProps, + mapDispatchToProps: MapDispatchToPropsFn | DP, + mergeProps: MergeProps, + options?: ?Options, + ): Connector; + + // ------------------------------------------------------------ + // Typings for Provider + // ------------------------------------------------------------ + + declare export class Provider extends React$Component<{ + store: Store, + children?: React$Node, + }> {} + + declare export function createProvider( + storeKey?: string, + subKey?: string, + ): Class>; + + // ------------------------------------------------------------ + // Typings for connectAdvanced() + // ------------------------------------------------------------ + + declare type ConnectAdvancedOptions = { + getDisplayName?: (name: string) => string, + methodName?: string, + renderCountProp?: string, + shouldHandleStateChanges?: boolean, + storeKey?: string, + withRef?: boolean, + }; + + declare type SelectorFactoryOptions = { + getDisplayName: (name: string) => string, + methodName: string, + renderCountProp: ?string, + shouldHandleStateChanges: boolean, + storeKey: string, + withRef: boolean, + displayName: string, + wrappedComponentName: string, + WrappedComponent: Com, + }; + + declare type MapStateToPropsEx = ( + state: S, + props: SP, + ) => RSP; + + declare type SelectorFactory< + Com: React$ComponentType<*>, + Dispatch, + S: Object, + OP: Object, + EFO: Object, + CP: Object, + > = ( + dispatch: Dispatch, + factoryOptions: SelectorFactoryOptions & EFO, + ) => MapStateToPropsEx; + + declare export function connectAdvanced< + Com: React$ComponentType<*>, + D, + S: Object, + OP: Object, + CP: Object, + EFO: Object, + ST: { [_: $Keys]: any }, + >( + selectorFactory: SelectorFactory, + connectAdvancedOptions: ?(ConnectAdvancedOptions & EFO), + ): (component: Com) => React$ComponentType & $Shape; +} diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_Provider.js b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_Provider.js new file mode 100644 index 0000000000..ff870d5aca --- /dev/null +++ b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_Provider.js @@ -0,0 +1,54 @@ +// @flow +import { describe, it } from 'flow-typed-test'; + +import React from "react"; +import { Provider, createProvider } from "react-redux"; + +describe('Provider', () => { + it('should give an error when the store is missing', () => { + // $ExpectError + ; + + // Also for custom providers + const CustomProvider: Class> = createProvider("ikea"); + + // $ExpectError + ; + }); +}); + +describe('Custom Store (eg for ThunkActions)', () => { + + // This represents a common typing for Thunk Actions. + + type Action = { type: 'SOME_ACTION' }; + type State = { state: string }; + + // ReduxStore should be imported from 'redux' but we can't do this with this + // test environment, so let's copy them once again... + declare type Redux$DispatchAPI = (action: A) => A; + declare type Redux$Dispatch = Redux$DispatchAPI; + declare type Redux$Reducer = (state: S | void, action: A) => S; + declare type Redux$Store> = { + dispatch: D; + getState(): S; + subscribe(listener: () => void): () => void; + replaceReducer(nextReducer: Redux$Reducer): void + }; + + // R = Result of a thunk action + type ThunkDispatch = (action: ThunkAction) => R; + type PlainDispatch = (action: Action) => Action; + type GetState = () => State; + type ThunkAction = (dispatch: Dispatch, GetState) => R; + // The `dispatch` function can accept either a plain action or a thunk action. + // This is similar to a type `(action: Action | ThunkAction) => any` except this + // allows to type the return value as well. + type Dispatch = PlainDispatch & ThunkDispatch; + type Store = Redux$Store; + + it('accepts a custom store', () => { + declare var store: Store; + ; + }); +}); diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js new file mode 100644 index 0000000000..cedbba00c8 --- /dev/null +++ b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js @@ -0,0 +1,551 @@ +// @flow +import React from "react"; +import { connect } from "react-redux"; + +function testPassingPropsToConnectedComponent() { + type OwnProps = {| + passthrough: number, + passthroughWithDefaultProp?: number, + forMapStateToProps: string + |} + type Props = { ...OwnProps, fromStateToProps: string}; + class Com extends React.Component { + static defaultProps = { passthroughWithDefaultProp: 123 }; + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + Connected.WrappedComponent; + ; + // OK without passthroughWithDefaultProp + ; + //$ExpectError wrong type for passthrough + ; + //$ExpectError wrong type for forMapStateToProps + ; + //$ExpectError wrong type for passthroughWithDefaultProp + ; + // Flow also erroneously complains about fromStateToProps + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + connect(mapStateToProps)(''); +} + +function doesNotRequireDefinedComponentToTypeCheck1case() { + type Props = { + stringProp: string, + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // Flow shows the main error in libdefs, + // but putting the suppression here does the trick + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + // in this case the explicit type arguments are required, + // otherwise Flow does not see the error + connect(mapStateToProps)(Component); +} + +function doesNotRequireDefinedComponentToTypeCheck2case() { + type Props = { + numProp: string, + }; + + const Component = ({ numProp }: Props) => { + return {numProp}; + }; + + const mapDispatchToProps = () => ({ + // Flow shows the main error in libdefs, + // but putting the suppression here does the trick + // $ExpectError wrong type for numProp + numProp: false, + }); + + // in this case the explicit type arguments are required, + // otherwise Flow does not see the error + connect(null, mapDispatchToProps)(Component); +} + +function doesNotRequireDefinedComponentToTypeCheck3case() { + type Props = { + stringProp: string, + numProp: number + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // Flow shows the main error in libdefs, + // but putting the suppression here does the trick + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + const mapDispatchToProps = () => ({ + // Flow shows the main error in libdefs, + // but putting the suppression here does the trick + // $ExpectError wrong type for numProp + numProp: false, + }); + + // in this case the explicit type arguments are required, + // otherwise Flow does not see the error + connect(mapStateToProps, mapDispatchToProps)(Component); +} + +function doesNotRequireDefinedComponentToTypeCheck4case() { + type Props = { + stringProp: string, + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // Flow shows the main error in libdefs, + // but putting the suppression here does the trick + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + // in this case the explicit type arguments are required, + // otherwise Flow does not see the error + connect(mapStateToProps, {})(Component); +} + +function doesNotRequireDefinedComponentToTypeCheck5case() { + type Props = { + stringProp: string + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = () => ({}); + const mapDispatchToProps = () => ({}); + + const mergeProps = () => ({ + // $ExpectError wrong type for stringProp + stringProp: true + }); + + connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); +} + +function testExactProps() { + type Props = {| + forMapStateToProps: string, + passthrough: number, + fromStateToProps: string + |}; + + class Com extends React.Component { + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = {| + forMapStateToProps: string, + passthrough: number, + |}; + + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + ; + //$ExpectError extra prop what exact props does not allow + ; + //$ExpectError wrong type for forMapStateToProps + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + connect(mapStateToProps)(''); +} + +function testWithStatelessFunctionalComponent() { + type Props = {passthrough: number, fromStateToProps: string}; + const Com = (props: Props) =>
{props.passthrough} {props.fromStateToProps}
+ + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the wrong type for passthroug, + // giving passthrough a number fixes the wrongly titled error. + //$ExpectError wrong type for passthrough + ; + //$ExpectError wrong type for forMapStateToProps + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + connect(mapStateToProps)(''); +} + +function testMapStateToPropsDoesNotNeedProps() { + type Props = {passthrough: number, fromStateToProps: string}; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + + type State = {a: string} + const mapStateToProps = (state: State) => { + return { + fromStateToProps: state.a + } + } + + const Connected = connect(mapStateToProps)(Com); + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError component property passthrough not found + ; +} + +function testMapDispatchToProps() { + type Props = { + passthrough: number, + fromMapDispatchToProps: string, + fromMapStateToProps: string + }; + class Com extends React.Component { + render() { + return
+ {this.props.passthrough} + {this.props.fromMapDispatchToProps} + {this.props.fromMapStateToProps} +
; + } + } + + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: 'str' + state.a + } + } + type MapDispatchToPropsProps = {forMapDispatchToProps: string} + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const Connected = connect(mapStateToProps, mapDispatchToProps)(Com); + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMapDispatchToProps missing + ; +} + +function testMapDispatchToPropsWithoutMapStateToProps() { + type Props = { + passthrough: number, + fromMapDispatchToProps: string + }; + class Com extends React.Component { + render() { + return
+ {this.props.passthrough} + {this.props.fromMapDispatchToProps} +
; + } + } + + type MapDispatchToPropsProps = {forMapDispatchToProps: string}; + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const Connected = connect(null, mapDispatchToProps)(Com); + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError passthrough missing + ; + //$ExpectError forMapDispatchToProps missing + ; +} + +function testMapDispatchToPropsPassesActionCreators() { + type Props = { + passthrough: number, + dispatch1: (num: number) => void, + dispatch2: () => void + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + + const mapDispatchToProps = { + dispatch1: (num: number) => {}, + dispatch2: () => {} + }; + const Connected = connect(null, mapDispatchToProps)(Com); + ; + // Here Flow reports that `dispatch1` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError no passthrough + ; + + const mapDispatchToPropsWithoutDispatch2 = { + dispatch1: (num: number) => {} + }; + const Connected2 = connect(null, mapDispatchToPropsWithoutDispatch2)(Com); + // Here Flow reports that `dispatch1` is missing from props, + // while the real error is still the missing `dispatch2`, + // giving the `mapDispatchToProps` to connect above + // fixes the wrongly titled error. + //$ExpectError no dispatch2 + ; + + const mapDispatchToPropsWithWrongDispatch1 = { + dispatch1: (num: string) => {}, + dispatch2: () => {} + }; + const Connected3 = connect(null, mapDispatchToPropsWithWrongDispatch1)(Com); + // Here Flow reports that `dispatch1` is missing from props, + // while the real error is still the wrong type of `dispatch1`, + // giving `num` the correct type fixes the wrongly titled error. + //$ExpectError dispatch1 should be number + ; +} + +function testMapDispatchToPropsPassesActionCreatorsWithMapStateToProps() { + type Props = { + passthrough: number, + dispatch1: () => void, + dispatch2: () => void, + fromMapStateToProps: number + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + const mapDispatchToProps = { + dispatch1: () => {}, + dispatch2: () => {} + }; + const Connected = connect(mapStateToProps, mapDispatchToProps)(Com); + ; + // Here Flow reports that `fromStateToProps` is missing from props, + // while the real error is still the missing passthroug property, + // giving the passthrough property fixes the wrongly titled error. + //$ExpectError no passthrough + ; + + const mapDispatchToProps2 = { + dispatch1: () => {} + }; + const Connected2 = connect(mapStateToProps, mapDispatchToProps2)(Com); + // Here Flow reports that `dispatch1` is missing from props, + // while the real error is still the missing `dispatch2`, + // fixing the original issue fixes the wrongly titled error. + //$ExpectError no dispatch2 + ; +} + +function testMapDispatchToPropsPassesActionCreatorsWithMapStateToPropsAndMergeProps() { + type Props = { + passthrough: number, + dispatch1: () => void, + dispatch2: () => void, + fromMapStateToProps: number, + fromMergeProps: number + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + const mapDispatchToProps = { + dispatch1: () => {}, + dispatch2: () => {} + }; + const mergeProps = (stateProps, dispatchProps, ownProps: {forMergeProps: number}) => { + return Object.assign({}, stateProps, dispatchProps, { fromMergeProps: 123 }); + } + const Connected = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Com); + ; + // Here Flow reports that `forMapStateToProps` is missing from props, + // while the real error is still the missing `passthrough`, + // fixing the original issue fixes the wrongly titled error. + //$ExpectError no passthrough + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMergeProps is missing + ; + //$ExpectError forMergeProps is wrong type + ; + + const mapDispatchToProps2 = { + dispatch1: () => {} + }; + const Connected2 = connect(mapStateToProps, mapDispatchToProps2)(Com); + // Here Flow reports that `dispatch1` is missing from props, + // while the real error is still the missing `dispatch2`, + // fixing the original issue fixes the wrongly titled error. + //$ExpectError no dispatch2 + ; +} + +function testMergeProps() { + type Props = { + fromMergeProps: number, + }; + class Com extends React.Component { + render() { + return
+ {this.props.fromMergeProps} +
; + } + } + + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + type MapDispatchToPropsProps = {forMapDispatchToProps: string} + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const mergeProps = (stateProps, dispatchProps, ownProps: {forMergeProps: number}) => { + return {fromMergeProps: 123}; + } + const Connected = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Com); + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMergeProps is missing + ; + //$ExpectError forMapDispatchToProps is missing + ; + //$ExpectError forMapDispatchToProps is wrong type + ; +} + +function testOptions() { + class Com extends React.Component<{}> { + render() { + return
; + } + } + connect(null, null, null, {pure: true})(Com); + connect(null, null, null, {withRef: true})(Com); + connect(null, null, null, {pure: false, withRef: false})(Com); + // $ExpectError wrong type + connect(null, null, null, {pure: 123})(Com); + // $ExpectError wrong type + connect(null, null, null, {ref: 123})(Com); + // $ExpectError wrong key + connect(null, null, null, {wrongKey: true})(Com); +} + +function testHoistConnectedComponent() { + type Props = {passthrough: number, passthroughWithDefaultProp: number, fromStateToProps: string}; + class Com extends React.Component { + static defaultProps = { passthroughWithDefaultProp: 123 }; + static myStatic = 1; + + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + // OK without passthroughWithDefaultProp + ; + // OK with passthroughWithDefaultProp + ; + // OK with declared static property + Connected.myStatic; +} diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectAdvanced.js b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectAdvanced.js new file mode 100644 index 0000000000..1e954aaf1d --- /dev/null +++ b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectAdvanced.js @@ -0,0 +1,124 @@ +// @flow +import React from "react"; +import { connectAdvanced } from "react-redux"; + +function testConnectAdvanced() { + type Props = {fromStateToProps: string, fromInputProps: string}; + class Com extends React.Component { + render() { + return
{this.props.fromInputProps} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = { + fromInputProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromInputProps: 'str' + props.fromInputProps, + fromStateToProps: 'str' + state.a + } + }; + + const selectorFactory = (dispatch: *, selectorFactoryOptions: *) => { + const { + getDisplayName, + methodName, + renderCountProp, + shouldHandleStateChanges, + storeKey, + withRef, + displayName, + wrappedComponentName, + }: { + getDisplayName: (name: string) => string, + methodName: string, + renderCountProp: ?string, + shouldHandleStateChanges: boolean, + storeKey: string, + withRef: boolean, + displayName: string, + wrappedComponentName: string, + } = selectorFactoryOptions; + return mapStateToProps; + } + + const Connected = connectAdvanced(selectorFactory)(Com); + ; + //$ExpectError expects props to match second argument of mapStateToProps + ; + //$ExpectError takes in only React components + connectAdvanced(selectorFactory)(''); +} + +function testConnectAdvancedWithStatelessFunctionalComponent() { + type Props = {fromStateToProps: string, fromInputProps: string}; + const Com = (props: Props) =>
{props.fromInputProps} {props.fromStateToProps}
; + + type State = {a: number}; + type InputProps = { + fromInputProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromInputProps: 'str' + props.fromInputProps, + fromStateToProps: 'str' + state.a + } + }; + + const selectorFactory = (dispatch: *, selectorFactoryOptions: *) => { + return mapStateToProps; + } + + const Connected = connectAdvanced(selectorFactory)(Com); + ; + //$ExpectError expects props to match second argument of mapStateToProps + ; +} + +function testConnectAdvancedConnectOptions() { + const selectorFactory = () => () => ({}); + connectAdvanced(selectorFactory, { + getDisplayName: (name: string) => name + name, + methodName: 'methodName', + renderCountProp: 'renderCount', + shouldHandleStateChanges: false, + storeKey: 'storeKey', + withRef: false, + }); + + //$ExpectError getDisplayName must take a string + connectAdvanced(selectorFactory, {getDisplayName: (name: number) => name + name}); + + //$ExpectError getDisplayName must return a string + connectAdvanced(selectorFactory, {getDisplayName: (name: string) => name.length}); + + //$ExpectError methodName must be a string + connectAdvanced(selectorFactory, {methodName: 5}); + + //$ExpectError renderCountProp must be a string + connectAdvanced(selectorFactory, {renderCountProp: 5}); + + //$ExpectError shouldHandleStateChanges must be defined if passed in + connectAdvanced(selectorFactory, {shouldHandleStateChanges: null}); + + //$ExpectError storeKey must be a string + connectAdvanced(selectorFactory, {storeKey: 5}); + + //$ExpectError withRef must be defined if passed in + connectAdvanced(selectorFactory, {withRef: null}); + + connectAdvanced(selectorFactory, {otherOption: "other options are allowed"}); +} + +function testConnectAdvancedExtraOptions() { + const selectorFactory = (dispatch: *, selectorFactoryOptions: *) => { + const { otherOption }: {otherOption: string} = selectorFactoryOptions; + return () => ({}); + } + + connectAdvanced(selectorFactory, {otherOption: "other options typecheck too"}); + //$ExpectError selectorFactory expects otherOption to be a specific type + connectAdvanced(selectorFactory, {otherOption: 5}); +} diff --git a/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectExported.js b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectExported.js new file mode 100644 index 0000000000..819fe41d6a --- /dev/null +++ b/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connectExported.js @@ -0,0 +1,603 @@ +// @flow +import React from "react"; +import { connect } from "react-redux"; + +export let e = [] + +function testPassingPropsToConnectedComponent() { + type OwnProps = {| + passthrough: number, + passthroughWithDefaultProp?: number, + forMapStateToProps: string + |} + type Props = { ...OwnProps, fromStateToProps: string}; + class Com extends React.Component { + static defaultProps = { passthroughWithDefaultProp: 123 }; + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + e.push(Connected); + Connected.WrappedComponent; + ; + // OK without passthroughWithDefaultProp + ; + //$ExpectError wrong type for passthrough + ; + //$ExpectError wrong type for forMapStateToProps + ; + //$ExpectError wrong type for passthroughWithDefaultProp + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + const Connected2 = connect(mapStateToProps)(''); + e.push(Connected2); +} + +function doesNotRequireDefinedComponentToTypeCheck1case() { + type Props = { + stringProp: string, + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + const Connected = connect(mapStateToProps)(Component); + ; + e.push(Connected); +} + +function doesNotRequireDefinedComponentToTypeCheck2case() { + type Props = { + numProp: string, + }; + + const Component = ({ numProp }: Props) => { + return {numProp}; + }; + + const mapDispatchToProps = () => ({ + // $ExpectError wrong type for numProp + numProp: false, + }); + + const Connected = connect(null, mapDispatchToProps)(Component); + ; + e.push(Connected); +} + +function doesNotRequireDefinedComponentToTypeCheck3case() { + type Props = { + stringProp: string, + numProp: number + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + const mapDispatchToProps = () => ({ + // $ExpectError wrong type for numProp + numProp: false, + }); + + const Connected = connect(mapStateToProps, mapDispatchToProps)(Component); + ; + e.push(Connected); +} + +function doesNotRequireDefinedComponentToTypeCheck4case() { + type Props = { + stringProp: string, + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = (state: {}) => ({ + // $ExpectError wrong type for stringProp + stringProp: false, + }); + + const Connected = connect(mapStateToProps, {})(Component); + ; + e.push(Connected); +} + +function doesNotRequireDefinedComponentToTypeCheck5case() { + type Props = { + stringProp: string + }; + + const Component = ({ stringProp }: Props) => { + return {stringProp}; + }; + + const mapStateToProps = () => ({}); + const mapDispatchToProps = () => ({}); + + const mergeProps = () => ({ + // $ExpectError wrong type for stringProp + stringProp: true + }); + + const Connected = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); + ; + e.push(Connected); +} + +function testExactProps() { + type OwnProps = {| + passthrough: number, + forMapStateToProps: string, + |}; + type Props = {| + ...OwnProps, + fromStateToProps: string + |}; + + class Com extends React.Component { + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = {| + forMapStateToProps: string, + passthrough: number, + |}; + + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + e.push(Connected); + ; + //$ExpectError extraProp what exact props does not allow + ; + //$ExpectError wrong type for forMapStateToProps + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + const Connected2 = connect(mapStateToProps)(''); + e.push(Connected2); +} + +function testWithStatelessFunctionalComponent() { + type OwnProps = {| + passthrough: number, + forMapStateToProps: string, + |}; + type Props = { + ...OwnProps, + fromStateToProps: string + }; + const Com = (props: Props) =>
{props.passthrough} {props.fromStateToProps}
+ + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + e.push(Connected); + ; + //$ExpectError wrong type for passthrough + ; + //$ExpectError wrong type for forMapStateToProps + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError takes in only React components + const Connected2 = connect(mapStateToProps)(''); + e.push(Connected2); +} + +function testMapStateToPropsDoesNotNeedProps() { + type OwnProps = {| + passthrough: number + |}; + type Props = { + ...OwnProps, + fromStateToProps: string + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + + type State = {a: string} + const mapStateToProps = (state: State) => { + return { + fromStateToProps: state.a + } + } + + const Connected = connect(mapStateToProps)(Com); + e.push(Connected); + ; + //$ExpectError component property passthrough not found + ; +} + +function testMapDispatchToProps() { + type OwnProps = {| + passthrough: number, + forMapStateToProps: string, + forMapDispatchToProps: string + |}; + type Props = { + ...OwnProps, + fromMapDispatchToProps: string, + fromMapStateToProps: string + }; + class Com extends React.Component { + render() { + return
+ {this.props.passthrough} + {this.props.fromMapDispatchToProps} + {this.props.fromMapStateToProps} +
; + } + } + + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: 'str' + state.a + } + } + type MapDispatchToPropsProps = {forMapDispatchToProps: string} + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const Connected = connect(mapStateToProps, mapDispatchToProps)(Com); + e.push(Connected); + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMapDispatchToProps missing + ; +} + +function testMapDispatchToPropsWithoutMapStateToProps() { + type OwnProps = {| + passthrough: number, + forMapStateToProps: string, + forMapDispatchToProps: string, + |}; + type Props = { + ...OwnProps, + fromMapDispatchToProps: string + }; + class Com extends React.Component { + render() { + return
+ {this.props.passthrough} + {this.props.fromMapDispatchToProps} +
; + } + } + + type MapDispatchToPropsProps = {forMapDispatchToProps: string}; + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const Connected = connect(null, mapDispatchToProps)(Com); + e.push(Connected); + ; + //$ExpectError passthrough missing + ; + //$ExpectError forMapDispatchToProps missing + ; +} + +function testMapDispatchToPropsPassesActionCreators() { + type OwnProps = {| + passthrough: number, + |}; + type Props = { + ...OwnProps, + dispatch1: (num: number) => void, + dispatch2: () => void + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + + const mapDispatchToProps = { + dispatch1: (num: number) => {}, + dispatch2: () => {} + }; + const Connected = connect(null, mapDispatchToProps)(Com); + e.push(Connected); + ; + //$ExpectError no passthrough + ; + + const mapDispatchToPropsWithoutDispatch2 = { + dispatch1: (num: number) => {} + }; + //$ExpectError no dispatch2 + const Connected2 = connect(null, mapDispatchToPropsWithoutDispatch2)(Com); + e.push(Connected2); + ; + + const mapDispatchToPropsWithWrongDispatch1 = { + //$ExpectError dispatch1 should be number + dispatch1: (num: string) => {}, + dispatch2: () => {} + }; + const Connected3 = connect(null, mapDispatchToPropsWithWrongDispatch1)(Com); + e.push(Connected3); + ; +} + +function testMapDispatchToPropsPassesActionCreatorsWithMapStateToProps() { + type OwnProps = {| + passthrough: number, + forMapStateToProps: string + |}; + type Props = { + ...OwnProps, + dispatch1: () => void, + dispatch2: () => void, + fromMapStateToProps: number + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + const mapDispatchToProps = { + dispatch1: () => {}, + dispatch2: () => {} + }; + const Connected = connect(mapStateToProps, mapDispatchToProps)(Com); + e.push(Connected); + ; + //$ExpectError no passthrough + ; + + const mapDispatchToProps2 = { + dispatch1: () => {} + }; + //$ExpectError no dispatch2 + const Connected2 = connect(mapStateToProps, mapDispatchToProps2)(Com); + e.push(Connected2); + ; +} + +function testMapDispatchToPropsPassesActionCreatorsWithMapStateToPropsAndMergeProps() { + type OwnProps1 = {| + passthrough: number, + forMapStateToProps: string, + forMergeProps: number + |}; + type OwnProps2 = {| + passthrough: number, + forMapStateToProps: string, + |}; + type Props = { + passthrough: number, + dispatch1: () => void, + dispatch2: () => void, + fromMapStateToProps: number, + fromMergeProps: number + }; + class Com extends React.Component { + render() { + return
{this.props.passthrough}
; + } + } + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + const mapDispatchToProps = { + dispatch1: () => {}, + dispatch2: () => {} + }; + const mergeProps = (stateProps, dispatchProps, ownProps: {forMergeProps: number}) => { + return Object.assign({}, stateProps, dispatchProps, { fromMergeProps: 123 }); + } + const Connected = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Com); + e.push(Connected); + ; + //$ExpectError no passthrough + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMergeProps is missing + ; + //$ExpectError forMergeProps is wrong type + ; + + const mapDispatchToProps2 = { + dispatch1: () => {} + }; + //$ExpectError no dispatch2 + const Connected2 = connect(mapStateToProps, mapDispatchToProps2)(Com); + e.push(Connected2); + ; +} + +function testMergeProps() { + type OwnProps = {| + forMapStateToProps: string, + forMapDispatchToProps: string, + forMergeProps: number + |}; + type Props = { + fromMergeProps: number, + }; + class Com extends React.Component { + render() { + return
+ {this.props.fromMergeProps} +
; + } + } + + type State = {a: number} + type MapStateToPropsProps = {forMapStateToProps: string} + const mapStateToProps = (state: State, props: MapStateToPropsProps) => { + return { + fromMapStateToProps: state.a + } + } + type MapDispatchToPropsProps = {forMapDispatchToProps: string} + const mapDispatchToProps = (dispatch: *, ownProps: MapDispatchToPropsProps) => { + return {fromMapDispatchToProps: ownProps.forMapDispatchToProps} + } + const mergeProps = (stateProps, dispatchProps, ownProps: {forMergeProps: number}) => { + return {fromMergeProps: 123}; + } + const Connected = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Com); + e.push(Connected); + ; + //$ExpectError forMapStateToProps missing + ; + //$ExpectError forMergeProps is missing + ; + //$ExpectError forMapDispatchToProps is missing + ; + //$ExpectError forMapDispatchToProps is wrong type + ; +} + +function testOptions() { + class Com extends React.Component<{}> { + render() { + return
; + } + } + // here in Props comes dispatch property + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {pure: true})(Com)); + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {withRef: true})(Com)); + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {pure: false, withRef: false})(Com)); + // $ExpectError wrong type + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {pure: 123})(Com)); + // $ExpectError wrong type + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {ref: 123})(Com)); + // $ExpectError wrong key + e.push(connect<{}, {||}, _,_,_,_>(null, null, null, {wrongKey: true})(Com)); +} + +function testDispatch() { + type Props = { + dispatch: empty => empty + } + class Com extends React.Component { + render() { + return
; + } + } + e.push(connect()(Com)); +} +function testNoDispatch() { + type Props = {||} + class Com extends React.Component { + render() { + return
; + } + } + // $ExpectError property `dispatch` is missing in `Props` + e.push(connect()(Com)); +} + +function testHoistConnectedComponent() { + type OwnProps = {| + passthrough: number, + passthroughWithDefaultProp: number, + forMapStateToProps: string + |}; + type Props = { + ...OwnProps, + fromStateToProps: string + }; + class Com extends React.Component { + static defaultProps = { passthroughWithDefaultProp: 123 }; + static myStatic = 1; + + render() { + return
{this.props.passthrough} {this.props.fromStateToProps}
; + } + } + + type State = {a: number}; + type InputProps = { + forMapStateToProps: string + }; + const mapStateToProps = (state: State, props: InputProps) => { + return { + fromStateToProps: 'str' + state.a + } + }; + + const Connected = connect(mapStateToProps)(Com); + e.push(Connected); + // $ExpectError should be OK without passthroughWithDefaultProp + ; + // OK with passthroughWithDefaultProp + ; + // OK with declared static property + Connected.myStatic; +} From 0c27d3bc32462827c6c0c5ce942a17d1167ea9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20=E2=80=9CBeau=E2=80=9D=20Collins?= Date: Thu, 3 Jan 2019 10:03:00 -0800 Subject: [PATCH 4/4] Fixing lodash defs for flow 0.88.0+ (#3020) * Fixing lodash defs for flow 0.88.0+ * Folders are correctly named now * Return value is a boolean * comment was used to trigger tests * More correct partial definitions * More generic function types * Better generics for functions * Using any as mixed fails type captures --- .../flow_v0.63.x-/lodash_v4.x.x.js | 72 +++++++++---------- .../test_does-not-fail-on-null-v4.x.x.js | 6 +- .../flow_v0.63.x-/test_lodash-v4.x.x.js | 7 +- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/lodash_v4.x.x.js b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/lodash_v4.x.x.js index 50631683c1..453c3d257e 100644 --- a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/lodash_v4.x.x.js +++ b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/lodash_v4.x.x.js @@ -158,7 +158,7 @@ declare module "lodash" { declare type NestedArray = Array>; - declare type matchesIterateeShorthand = Object; + declare type matchesIterateeShorthand = {[key: any]: any}; declare type matchesPropertyIterateeShorthand = [string, any]; declare type propertyIterateeShorthand = string; @@ -746,8 +746,8 @@ declare module "lodash" { shuffle(array: ?Array): Array; shuffle(object: T): Array; size(collection: $ReadOnlyArray | Object | string): number; - some(array: ?$ReadOnlyArray, predicate?: Predicate): boolean; some(array: void | null, predicate?: ?Predicate): false; + some(array: ?$ReadOnlyArray, predicate?: Predicate): boolean; some( object?: ?T, predicate?: OPredicate @@ -776,33 +776,33 @@ declare module "lodash" { after(n: number, fn: Function): Function; ary(func: Function, n?: number): Function; before(n: number, fn: Function): Function; - bind(func: Function, thisArg: any, ...partials: Array): Function; + bind any>(func: F, thisArg: any, ...partials: Array): F; bindKey(obj?: ?Object, key?: ?string, ...partials?: Array): Function; curry: Curry; curry(func: Function, arity?: number): Function; curryRight(func: Function, arity?: number): Function; - debounce(func: F, wait?: number, options?: DebounceOptions): F; - defer(func: Function, ...args?: Array): TimeoutID; + debounce any>(func: F, wait?: number, options?: DebounceOptions): F; + defer(func: (...any[]) => any, ...args?: Array): TimeoutID; delay(func: Function, wait: number, ...args?: Array): TimeoutID; - flip(func: Function): Function; - memoize(func: F, resolver?: Function): F; - negate(predicate: Function): Function; - once(func: Function): Function; + flip(func: (...any[]) => R): (...any[]) => R; + memoize(func: (...A) => R, resolver?: (...A) => any): (...A) => R; + negate(predicate: (...A) => R): (...A) => boolean; + once any>(func: F): F; overArgs(func?: ?Function, ...transforms?: Array): Function; overArgs(func?: ?Function, transforms?: ?Array): Function; - partial(func: Function, ...partials: any[]): Function; - partialRight(func: Function, ...partials: Array): Function; - partialRight(func: Function, partials: Array): Function; + partial(func: (...any[]) => R, ...partials: any[]): (...any[]) => R; + partialRight(func: (...any[]) => R, ...partials: Array): (...any[]) => R; + partialRight(func: (...any[]) => R, partials: Array): (...any[]) => R; rearg(func: Function, ...indexes: Array): Function; rearg(func: Function, indexes: Array): Function; rest(func: Function, start?: number): Function; spread(func: Function): Function; - throttle( - func: Function, + throttle any>( + func: F, wait?: number, options?: ThrottleOptions - ): Function; - unary(func: Function): Function; + ): F; + unary any>(func: F): F; wrap(value?: any, wrapper?: ?Function): Function; // Lang @@ -891,12 +891,10 @@ declare module "lodash" { isNull(value: any): false; isNumber(value: number): true; isNumber(value: any): false; - isObject(value: Object): true; - isObject(value: any): false; + isObject(value: any): boolean; isObjectLike(value: void | null): false; isObjectLike(value: any): boolean; - isPlainObject(value: Object): true; - isPlainObject(value: any): false; + isPlainObject(value: any): boolean; isRegExp(value: RegExp): true; isRegExp(value: any): false; isSafeInteger(value: number): boolean; @@ -1066,6 +1064,7 @@ declare module "lodash" { ): Object; at(object?: ?Object, ...paths: Array): Array; at(object?: ?Object, paths: Array): Array; + create(prototype: void | null, properties: void | null): {}; create(prototype: T, properties: Object): $Supertype; create(prototype: any, properties: void | null): {}; defaults(object?: ?Object, ...sources?: Array): Object; @@ -1283,8 +1282,8 @@ declare module "lodash" { iteratee?: ?OIteratee<*>, accumulator?: ?any ): {}; - unset(object: Object, path?: ?Array | ?string): boolean; unset(object: void | null, path?: ?Array | ?string): true; + unset(object: Object, path?: ?Array | ?string): boolean; update(object: Object, path: string[] | string, updater: Function): Object; update( object: T, @@ -1393,13 +1392,13 @@ declare module "lodash" { cond(pairs?: ?NestedArray): Function; conforms(source?: ?Object): Function; constant(value: T): () => T; - defaultTo( + defaultTo(value: T1, defaultValue: T2): T2; + defaultTo( value: T1, defaultValue: T2 ): T1; // NaN is a number instead of its own type, otherwise it would behave like null/void defaultTo(value: T1, defaultValue: T2): T1 | T2; - defaultTo(value: T1, defaultValue: T2): T2; flow: $ComposeReverse & ((funcs: Array) => Function); flowRight: $Compose & ((funcs: Array) => Function); identity(value: T): T; @@ -1608,7 +1607,7 @@ declare module "lodash/fp" { declare type NestedArray = Array>; - declare type matchesIterateeShorthand = Object; + declare type matchesIterateeShorthand = {[string | number]: any}; declare type matchesPropertyIterateeShorthand = [string, any]; declare type propertyIterateeShorthand = string; @@ -2351,14 +2350,14 @@ declare module "lodash/fp" { curryRight(func: Function): Function; curryRightN(arity: number): (func: Function) => Function; curryRightN(arity: number, func: Function): Function; - debounce(wait: number): (func: F) => F; - debounce(wait: number, func: F): F; - defer(func: Function): TimeoutID; + debounce(wait: number): (func: (...A) => R) => (...A) => R; + debounce(wait: number, func: (...A) => R): (...A) => R; + defer(func: (...any[]) => any): TimeoutID; delay(wait: number): (func: Function) => TimeoutID; delay(wait: number, func: Function): TimeoutID; flip(func: Function): Function; memoize(func: F): F; - negate(predicate: Function): Function; + negate(predicate: (...A) => R): (...A) => boolean; complement(predicate: Function): Function; once(func: Function): Function; overArgs(func: Function): (transforms: Array) => Function; @@ -2379,9 +2378,9 @@ declare module "lodash/fp" { apply(func: Function): Function; spreadFrom(start: number): (func: Function) => Function; spreadFrom(start: number, func: Function): Function; - throttle(wait: number): (func: Function) => Function; - throttle(wait: number, func: Function): Function; - unary(func: Function): Function; + throttle(wait: number): (func: (...A) => R) => (...A) => R; + throttle(wait: number, func: (...A) => R): (...A) => R; + unary(func: (T, ...any[]) => R): (T) => R; wrap(wrapper: Function): (value: any) => Function; wrap(wrapper: Function, value: any): Function; @@ -2482,8 +2481,7 @@ declare module "lodash/fp" { ): boolean; isError(value: any): boolean; isFinite(value: any): boolean; - isFunction(value: Function): true; - isFunction(value: number | string | void | null | Object): false; + isFunction(value: any): boolean; isInteger(value: any): boolean; isLength(value: any): boolean; isMap(value: any): boolean; @@ -3154,18 +3152,18 @@ declare module "lodash/fp" { cond(pairs: NestedArray): Function; constant(value: T): () => T; always(value: T): () => T; - defaultTo( + defaultTo(defaultValue: T2): (value: T1) => T2; + defaultTo(defaultValue: T2, value: T1): T2; + defaultTo( defaultValue: T2 ): (value: T1) => T1; - defaultTo( + defaultTo( defaultValue: T2, value: T1 ): T1; // NaN is a number instead of its own type, otherwise it would behave like null/void defaultTo(defaultValue: T2): (value: T1) => T1 | T2; defaultTo(defaultValue: T2, value: T1): T1 | T2; - defaultTo(defaultValue: T2): (value: T1) => T2; - defaultTo(defaultValue: T2, value: T1): T2; flow: $ComposeReverse & ((funcs: Array) => Function); pipe: $ComposeReverse & ((funcs: Array) => Function); flowRight: $Compose & ((funcs: Array) => Function); diff --git a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_does-not-fail-on-null-v4.x.x.js b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_does-not-fail-on-null-v4.x.x.js index edb91a9425..f2c0a59e9d 100644 --- a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_does-not-fail-on-null-v4.x.x.js +++ b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_does-not-fail-on-null-v4.x.x.js @@ -434,7 +434,7 @@ import first from "lodash/first"; (isEqualWith(null, null, null): boolean); (isError(null): false); (isFinite(null): false); -(isFunction(null): false); +(isFunction(null): boolean); (isInteger(null): false); (isLength(null): false); (isMap(null): false); @@ -445,9 +445,9 @@ import first from "lodash/first"; (isNil(null): true); (isNull(null): true); (isNumber(null): false); -(isObject(null): false); +(isObject(null): boolean); (isObjectLike(null): false); -(isPlainObject(null): false); +(isPlainObject(null): boolean); (isRegExp(null): false); (isSafeInteger(null): false); (isSet(null): false); diff --git a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_lodash-v4.x.x.js b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_lodash-v4.x.x.js index b22e6ee49d..e992ac36d6 100644 --- a/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_lodash-v4.x.x.js +++ b/definitions/npm/lodash_v4.x.x/flow_v0.63.x-/test_lodash-v4.x.x.js @@ -106,9 +106,6 @@ opaque type O = string; const v: { [O]: number } = { x: 1, y: 2 }; find(v, { x: 3 }); -// $ExpectError undefined. This type is incompatible with object type. -var result: Object = find(users, "active"); - /** * _.find examples from the official doc */ @@ -377,9 +374,9 @@ boolTrue = isString(undefined); /** * _.find */ -find([1, 2, 3], x => x == 1); +(find([1, 2, 3], x => x == 1): void | number); // $ExpectError number. This type is incompatible with function type. -find([1, 2, 3], 1); +(find([1, 2, 3], 1): void | number); // Copy pasted tests from iflow-lodash var nums: number[] = [1, 2, 3, 4, 5, 6];