diff --git a/react-redux/react-redux-tests.tsx b/react-redux/react-redux-tests.tsx index 3254e6ec7..9528a7aca 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; @@ -270,11 +271,3 @@ let anElement: ReactElement; 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; - diff --git a/react-redux/react-redux.d.ts b/react-redux/react-redux.d.ts index 767b6b109..a052daada 100644 --- a/react-redux/react-redux.d.ts +++ b/react-redux/react-redux.d.ts @@ -7,40 +7,68 @@ /// declare module "react-redux" { - import { Component } from 'react'; + import { Component, ComponentClass, Props, ReactNode } from 'react'; import { Store, Dispatch, ActionCreator } from 'redux'; - export class ElementClass extends Component { } - export interface ClassDecorator { - (component: T): T + /** Generic decorator, that receives T = original props, U = own props */ + interface ComponentDecorator, U 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 { +

(component: ComponentClass

): ComponentClass

; } /** * 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 responsability 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): ClassDecorator; + */ + export function connect(): InferableComponentDecorator; + export function connect, U extends Props, V extends Props>( + mapStateToProps: MapStateToProps, + mapDispatchToProps?: MapDispatchToPropsFunction|MapDispatchToPropsObject + ): ComponentDecorator; + export function connect, U extends Props, V extends Props>( + mapStateToProps: MapStateToProps, + mapDispatchToProps: MapDispatchToPropsFunction|MapDispatchToPropsObject, + mergeProps: MergeProps, + options?: Options + ): ComponentDecorator; - interface MapStateToProps { - (state: any, ownProps?: any): any; + interface MapStateToProps { + (state: any, ownProps?: V): T; } - interface MapDispatchToPropsFunction { - (dispatch: Dispatch, ownProps?: any): any; + interface MapDispatchToPropsFunction { + (dispatch: Dispatch, ownProps?: V): U; } interface MapDispatchToPropsObject { [name: string]: ActionCreator; } - interface MergeProps { - (stateProps: any, dispatchProps: any, ownProps: any): any; + interface MergeProps { + (stateProps: T, dispatchProps: U, ownProps: V): T & U; } interface Options { @@ -54,16 +82,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 { } }