diff --git a/react-redux/react-redux-tests.tsx b/react-redux/react-redux-tests.tsx index 9ba06ac21d..2ffb30169e 100644 --- a/react-redux/react-redux-tests.tsx +++ b/react-redux/react-redux-tests.tsx @@ -94,6 +94,7 @@ interface TodoProps { } interface DispatchProps { addTodo(userId: number, text: string): void; + action: Function; } declare var actionCreators: () => { action: Function; @@ -275,14 +276,6 @@ class NonComponent {} // this doesn't compile //connect()(NonComponent); -// connect()(SomeClass) has the same constructor as SomeClass itself -class SomeClass extends Component { - constructor(public foo: string) { super() } - public bar: number; -} -let bar: number = new (connect()(SomeClass))("foo").bar; - - // stateless functions interface HelloMessageProps { name: string; } function HelloMessage(props: HelloMessageProps) { diff --git a/react-redux/react-redux.d.ts b/react-redux/react-redux.d.ts index 9c46fd10c7..9bb8f7d820 100644 --- a/react-redux/react-redux.d.ts +++ b/react-redux/react-redux.d.ts @@ -7,39 +7,75 @@ /// declare module "react-redux" { - import { ComponentClass, Component, StatelessComponent } from 'react'; + import { ComponentClass, Component, StatelessComponent, Props, ReactNode } from 'react'; import { Store, Dispatch, ActionCreator } from 'redux'; - export interface ComponentConstructDecorator

{ - |StatelessComponent

)>(component: TComponentConstruct): TComponentConstruct + interface ComponentDecorator, TOwnProps extends Props> { + (component: ComponentClass): ComponentClass; + } + + /** + * Decorator that infers the type from the original component + * + * Can't use the above decorator because it would default the type to {} + */ + export interface InferableComponentDecorator { + |StatelessComponent

)>(component: TComponentConstruct): TComponentConstruct; } /** * Connects a React component to a Redux store. + * + * - Without arguments, just wraps the component, without changing the behavior / props + * + * - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior + * is to override ownProps (as stated in the docs), so what remains is everything that's + * not a state or dispatch prop + * + * - When 3rd param is passed, we don't know if ownProps propagate and whether they + * should be valid component props, because it depends on mergeProps implementation. + * As such, it is the user's responsibility to extend ownProps interface from state or + * dispatch props or both when applicable + * * @param mapStateToProps * @param mapDispatchToProps * @param mergeProps * @param options - */ - export function connect

(mapStateToProps?: MapStateToProps, - mapDispatchToProps?: MapDispatchToPropsFunction|MapDispatchToPropsObject, - mergeProps?: MergeProps, - options?: Options): ComponentConstructDecorator

; + */ + export function connect(): InferableComponentDecorator; + export function connect< + TStateProps extends Props, + TDispatchProps extends Props, + TOwnProps extends Props + >( + mapStateToProps: MapStateToProps, + mapDispatchToProps?: MapDispatchToPropsFunction|MapDispatchToPropsObject + ): ComponentDecorator; + export function connect< + TStateProps extends Props, + TDispatchProps extends Props, + TOwnProps extends Props + >( + mapStateToProps: MapStateToProps, + mapDispatchToProps: MapDispatchToPropsFunction|MapDispatchToPropsObject, + mergeProps: MergeProps, + options?: Options + ): ComponentDecorator; - interface MapStateToProps { - (state: any, ownProps?: any): any; + interface MapStateToProps { + (state: any, ownProps?: TOwnProps): TStateProps; } - interface MapDispatchToPropsFunction { - (dispatch: Dispatch, ownProps?: any): any; + interface MapDispatchToPropsFunction { + (dispatch: Dispatch, ownProps?: TOwnProps): TDispatchProps; } interface MapDispatchToPropsObject { [name: string]: ActionCreator; } - interface MergeProps { - (stateProps: any, dispatchProps: any, ownProps: any): any; + interface MergeProps { + (stateProps: TStateProps, dispatchProps: TDispatchProps, ownProps: TOwnProps): TStateProps & TDispatchProps; } interface Options { @@ -53,16 +89,16 @@ declare module "react-redux" { pure: boolean; } - export interface Property { + export interface ProviderProps extends Props { /** * The single Redux store in your application. */ store?: Store; - children?: Function; + children?: ReactNode; } /** * Makes the Redux store available to the connect() calls in the component hierarchy below. */ - export class Provider extends Component { } + export class Provider extends Component { } }