Merge pull request #30760 from surgeboris/react-redux

[react-redux] fixed mistreating of action thunk creator parameters
This commit is contained in:
Andrew Casey 2018-12-07 15:14:54 -08:00 committed by GitHub
commit 72b4da337a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 133 additions and 46 deletions

View File

@ -2,7 +2,7 @@
// Project: https://github.com/mirrorjs/mirror
// Definitions by: Aaronphy <https://github.com/aaronphy>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import * as H from 'history';

View File

@ -2,7 +2,7 @@
// Project: https://github.com/bmealhouse/next-redux-saga
// Definitions by: Leo Cavalcante <https://github.com/leocavalcante>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import { ComponentType } from "react";

View File

@ -3,7 +3,7 @@
// Definitions by: Steve <https://github.com/stevegeek>
// Jungwoo-An <https://github.com/Jungwoo-An>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
/// <reference types="node" />

View File

@ -2,7 +2,7 @@
// Project: https://github.com/ratson/react-intl-redux
// Definitions by: Karol Janyst <https://github.com/LKay>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import { Action, AnyAction } from "redux"
import { Provider as ReduxProvider } from "react-redux"

View File

@ -2,7 +2,7 @@
// Project: https://github.com/JamieDixon/react-lifecycle-component
// Definitions by: Alexander Fisher <https://github.com/pixelshaded>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import { ComponentLifecycle, Component, ComponentClass } from 'react';
import { Connect } from 'react-redux';

View File

@ -4,7 +4,7 @@
// Artyom Stukans <https://github.com/artyomsv>
// Mika Kuitunen <https://github.com/kulmajaba>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import { Component } from 'react';
import { Action, Reducer } from 'redux';

View File

@ -13,7 +13,7 @@
// Anatoli Papirovski <https://github.com/apapirovski>
// Boris Sergeyev <https://github.com/surgeboris>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
// Known Issue:
// There is a known issue in TypeScript, which doesn't allow decorators to change the signature of the classes
@ -65,11 +65,11 @@ export type AdvancedComponentDecorator<TProps, TOwnProps> =
* DecorationTargetProps[P] definition, its definition will be that of InjectedProps[P]
*/
export type Matching<InjectedProps, DecorationTargetProps> = {
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P];
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P];
};
/**
@ -95,16 +95,16 @@ export type GetProps<C> = C extends ComponentType<infer P> ? P : never;
// Applies LibraryManagedAttributes (proper handling of defaultProps
// and propTypes), as well as defines WrappedComponent.
export type ConnectedComponentClass<C, P> = ComponentClass<JSX.LibraryManagedAttributes<C, P>> & {
WrappedComponent: C;
WrappedComponent: C;
};
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render. Also adds new prop requirements from TNeedsProps.
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> =
<C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>>(
component: C
) => ConnectedComponentClass<C, Omit<GetProps<C>, keyof Shared<TInjectedProps, GetProps<C>>> & TNeedsProps>;
<C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>>(
component: C
) => ConnectedComponentClass<C, Omit<GetProps<C>, keyof Shared<TInjectedProps, GetProps<C>>> & TNeedsProps>;
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
@ -112,14 +112,19 @@ export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> =
export type InferableComponentEnhancer<TInjectedProps> =
InferableComponentEnhancerWithProps<TInjectedProps, {}>;
export type InferThunkActionCreatorType<TActionCreator extends (...args: any[]) => any> =
TActionCreator extends (...args: infer TParams) => (...args: any[]) => infer TReturn
? (...args: TParams) => TReturn
: TActionCreator;
export type HandleThunkActionCreator<TActionCreator> =
TActionCreator extends (...args: any[]) => (...args: any[]) => any
? ReturnType<TActionCreator>
TActionCreator extends (...args: any[]) => any
? InferThunkActionCreatorType<TActionCreator>
: TActionCreator;
// redux-thunk middleware returns thunk's return value from dispatch call
// https://github.com/reduxjs/redux-thunk#composition
export type WithThunkActionCreators<TDispatchProps> =
export type ResolveThunks<TDispatchProps> =
TDispatchProps extends { [key: string]: any }
? {
[C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]>
@ -155,17 +160,27 @@ export interface Connect {
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: TDispatchProps,
): InferableComponentEnhancerWithProps<
WithThunkActionCreators<TDispatchProps>,
ResolveThunks<TDispatchProps>,
TOwnProps
>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: TDispatchProps,
): InferableComponentEnhancerWithProps<
TStateProps & WithThunkActionCreators<TDispatchProps>,
TStateProps & ResolveThunks<TDispatchProps>,
TOwnProps
>;
@ -203,21 +218,35 @@ export interface Connect {
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: Options<{}, TStateProps, TOwnProps>
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: TDispatchProps,
mergeProps: null | undefined,
options: Options<{}, TStateProps, TOwnProps>
): InferableComponentEnhancerWithProps<
WithThunkActionCreators<TDispatchProps>,
ResolveThunks<TDispatchProps>,
TOwnProps
>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: Options<State, TStateProps, TOwnProps>
): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: TDispatchProps,
mergeProps: null | undefined,
options: Options<State, TStateProps, TOwnProps>
): InferableComponentEnhancerWithProps<
TStateProps & WithThunkActionCreators<TDispatchProps>,
TStateProps & ResolveThunks<TDispatchProps>,
TOwnProps
>;
// tslint:enable:no-unnecessary-generics
@ -243,10 +272,12 @@ export type MapDispatchToProps<TDispatchProps, TOwnProps> =
MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | TDispatchProps;
export type MapDispatchToPropsFactory<TDispatchProps, TOwnProps> =
(dispatch: Dispatch<Action>, ownProps: TOwnProps) => MapDispatchToProps<TDispatchProps, TOwnProps>;
(dispatch: Dispatch<Action>, ownProps: TOwnProps) => MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
export type MapDispatchToPropsParam<TDispatchProps, TOwnProps> = MapDispatchToPropsFactory<TDispatchProps, TOwnProps> | MapDispatchToProps<TDispatchProps, TOwnProps>;
export type MapDispatchToPropsNonObject<TDispatchProps, TOwnProps> = MapDispatchToPropsFactory<TDispatchProps, TOwnProps> | MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
export type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> =
(stateProps: TStateProps, dispatchProps: TDispatchProps, ownProps: TOwnProps) => TMergedProps;

View File

@ -102,23 +102,79 @@ function MapDispatch() {
}
function MapDispatchWithThunkActionCreators() {
class TestComponent extends React.Component<{
foo: string,
onClick(): void,
thunkAction(): Promise<void>
}> {}
const mapDispatchToProps = () => ({
onClick: () => {},
thunkAction: () => async () => {}
const simpleAction = (payload: boolean) => ({
type: 'SIMPLE_ACTION',
payload,
});
const thunkAction = (param1: number, param2: string) => (
async (dispatch: Dispatch, { foo }: OwnProps) => {
return foo;
}
);
interface OwnProps {
foo: string;
}
interface TestComponentProps extends OwnProps {
simpleAction: typeof simpleAction;
thunkAction(param1: number, param2: string): Promise<string>;
}
class TestComponent extends React.Component<TestComponentProps> {}
const Test = connect(
null,
mapDispatchToProps,
const mapStateToProps = ({ foo }: { foo: string }) => ({ foo });
const mapDispatchToProps = { simpleAction, thunkAction };
const Test1 = connect(null, mapDispatchToProps)(TestComponent);
const Test2 = connect(mapStateToProps, mapDispatchToProps)(TestComponent);
const Test3 = connect(
null, mapDispatchToProps, null, { storeKey: 'somekey' }
)(TestComponent);
const Test4 = connect(
mapStateToProps, mapDispatchToProps, null, { storeKey: 'somekey' }
)(TestComponent);
const verify = <div>
<Test1 foo='bar' />;
<Test2 />
<Test3 foo='bar' />;
<Test4 />
</div>;
}
const verify = <Test foo='bar' />;
function MapManualDispatchThatLooksLikeThunk() {
interface OwnProps {
foo: string;
}
interface TestComponentProps extends OwnProps {
remove: (item: string) => () => object;
}
class TestComponent extends React.Component<TestComponentProps> {
render() {
return <div onClick={this.props.remove('someid')} />;
}
}
const mapStateToProps = ({ foo }: { foo: string }) => ({ foo });
function mapDispatchToProps(dispatch: Dispatch) {
return {
remove(item: string) {
return () => dispatch({ type: 'REMOVE_ITEM', item });
}
};
}
const Test1 = connect(null, mapDispatchToProps)(TestComponent);
const Test2 = connect(mapStateToProps, mapDispatchToProps)(TestComponent);
const Test3 = connect(
null, mapDispatchToProps, null, { storeKey: 'somekey' }
)(TestComponent);
const Test4 = connect(
mapStateToProps, mapDispatchToProps, null, { storeKey: 'somekey' }
)(TestComponent);
const verify = <div>
<Test1 foo='bar' />;
<Test2 />
<Test3 foo='bar' />;
<Test4 />
</div>;
}
function MapStateAndDispatchObject() {

View File

@ -4,7 +4,7 @@
// Shoya Tanaka <https://github.com/8398a7>
// Mykolas <https://github.com/mykolas>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import {
Store,

View File

@ -2,7 +2,7 @@
// Project: https://github.com/mjrussell/redux-auth-wrapper
// Definitions by: Karol Janyst <https://github.com/LKay>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import { ComponentClass, StatelessComponent, ComponentType, ReactType } from "react";

View File

@ -2,7 +2,7 @@
// Project: https://github.com/gaearon/redux-devtools
// Definitions by: Petryshyn Sergii <https://github.com/mc-petry>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import * as React from 'react';
import { GenericStoreEnhancer } from 'redux';

View File

@ -12,7 +12,7 @@
// Maddi Joyce <https://github.com/maddijoyce>
// Kamil Wojcik <https://github.com/smifun>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.9
// TypeScript Version: 3.0
import {
ComponentClass,
StatelessComponent,

View File

@ -2,7 +2,7 @@
// Project: https://github.com/erikras/redux-form
// Definitions by: Carson Full <https://github.com/carsonf>, Daniel Lytkin <https://github.com/aikoven>, Karol Janyst <https://github.com/LKay>, Luka Zakrajsek <https://github.com/bancek>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import {
ComponentClass,