diff --git a/react-redux/react-redux-tests.tsx b/react-redux/react-redux-tests.tsx new file mode 100644 index 0000000000..9ba06ac21d --- /dev/null +++ b/react-redux/react-redux-tests.tsx @@ -0,0 +1,293 @@ +/// +/// +/// +/// +/// +/// +/// + +import { Component, ReactElement } from 'react'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { Router, RouterState } from 'react-router'; +import { Store, Dispatch, bindActionCreators } from 'redux'; +import { connect, Provider } from 'react-redux'; +import objectAssign = require('object-assign'); + +// +// Quick Start +// https://github.com/rackt/react-redux/blob/master/docs/quick-start.md#quick-start +// + +interface CounterState { + counter: number; +} +declare var increment: Function; + +class Counter extends Component { + render() { + return ( + + ); + } +} + +function mapStateToProps(state: CounterState) { + return { + value: state.counter + }; +} + +// Which action creators does it want to receive by props? +function mapDispatchToProps(dispatch: Dispatch) { + return { + onIncrement: () => dispatch(increment()) + }; +} + +connect( + mapStateToProps, + mapDispatchToProps +)(Counter); + + +@connect(mapStateToProps) +class CounterContainer extends Component { + +} + +class App extends Component { + render(): JSX.Element { + // ... + return null; + } +} + +const targetEl = document.getElementById('root'); + +ReactDOM.render(( + + {() => } + +), targetEl); + +// +// API +// https://github.com/rackt/react-redux/blob/master/docs/api.md +// +declare var store: Store; +declare var routerState: RouterState; +declare var history: HistoryModule.History; +class MyRootComponent extends Component { + +} +class TodoApp extends Component { + +} +interface TodoState { + todos: string[]|string; +} +interface TodoProps { + userId: number; +} +interface DispatchProps { + addTodo(userId: number, text: string): void; +} +declare var actionCreators: () => { + action: Function; +} +declare var addTodo: () => { type: string; }; +declare var todoActionCreators: { [type: string]: (...args: any[]) => any; }; +declare var counterActionCreators: { [type: string]: (...args: any[]) => any; }; + +ReactDOM.render( + + {() => } + , + document.body +); + +//TODO: for React Router 0.13 +////TODO: error TS2339: Property 'run' does not exist on type 'typeof "react-router"'. +////TODO: error TS2339: Property 'HistoryLocation' does not exist on type 'typeof "react-router"'. +//declare var routes: any; +//Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here +// ReactDOM.render( +// +// {/* +// //TODO: error TS2339: Property 'routerState' does not exist on type 'RouteProp'. +// {() => } // note "routerState" here: important to pass it down +// */} +// , +// document.getElementById('root') +// ); +//}); + + +//TODO: for React Router 1.0 +ReactDOM.render( + + {() => ...} + , + targetEl +); + +// Inject just dispatch and don't listen to store + +connect()(TodoApp); + +// Inject dispatch and every field in the global state + +connect((state: TodoState) => state)(TodoApp); + +// Inject dispatch and todos + +function mapStateToProps2(state: TodoState) { + return { todos: state.todos }; +} + +export default connect(mapStateToProps2)(TodoApp); + +// Inject todos and all action creators (addTodo, completeTodo, ...) + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +connect(mapStateToProps2, actionCreators)(TodoApp); + +// Inject todos and all action creators (addTodo, completeTodo, ...) as actions + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mapDispatchToProps2(dispatch: Dispatch) { + return { actions: bindActionCreators(actionCreators, dispatch) }; +} + +connect(mapStateToProps2, mapDispatchToProps2)(TodoApp); + +// Inject todos and a specific action creator (addTodo) + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mapDispatchToProps3(dispatch: Dispatch) { + return bindActionCreators({ addTodo }, dispatch); +} + +connect(mapStateToProps2, mapDispatchToProps3)(TodoApp); + +// Inject todos, todoActionCreators as todoActions, and counterActionCreators as counterActions + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mapDispatchToProps4(dispatch: Dispatch) { + return { + todoActions: bindActionCreators(todoActionCreators, dispatch), + counterActions: bindActionCreators(counterActionCreators, dispatch) + }; +} + +connect(mapStateToProps2, mapDispatchToProps4)(TodoApp); + +// Inject todos, and todoActionCreators and counterActionCreators together as actions + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mapDispatchToProps5(dispatch: Dispatch) { + return { + actions: bindActionCreators(objectAssign({}, todoActionCreators, counterActionCreators), dispatch) + }; +} + +connect(mapStateToProps2, mapDispatchToProps5)(TodoApp); + +// Inject todos, and all todoActionCreators and counterActionCreators directly as props + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mapDispatchToProps6(dispatch: Dispatch) { + return bindActionCreators(objectAssign({}, todoActionCreators, counterActionCreators), dispatch); +} + +connect(mapStateToProps2, mapDispatchToProps6)(TodoApp); + +// Inject todos of a specific user depending on props + +function mapStateToProps3(state: TodoState, ownProps: TodoProps): TodoState { + return { todos: state.todos[ownProps.userId] }; +} + +connect(mapStateToProps3)(TodoApp); + +// Inject todos of a specific user depending on props, and inject props.userId into the action + +//function mapStateToProps(state) { +// return { todos: state.todos }; +//} + +function mergeProps(stateProps: TodoState, dispatchProps: DispatchProps, ownProps: TodoProps): DispatchProps & TodoState { + return objectAssign({}, ownProps, { + todos: stateProps.todos[ownProps.userId], + addTodo: (text: string) => dispatchProps.addTodo(ownProps.userId, text) + }); +} + +connect(mapStateToProps2, actionCreators, mergeProps)(TodoApp); + + + + + +interface TestProp { + property1: number; + someOtherProperty?: string; +} +interface TestState { + isLoaded: boolean; + state1: number; +} +class TestComponent extends Component { } +const WrappedTestComponent = connect()(TestComponent); + +// return value of the connect()(TestComponent) is of the type TestComponent +let ATestComponent: typeof TestComponent = null; +ATestComponent = TestComponent; +ATestComponent = WrappedTestComponent; + +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; + + +// stateless functions +interface HelloMessageProps { name: string; } +function HelloMessage(props: HelloMessageProps) { + return
Hello {props.name}
; +} +let ConnectedHelloMessage = connect()(HelloMessage); +ReactDOM.render(, document.getElementById('content')); +ReactDOM.render(, document.getElementById('content')); diff --git a/react-redux/react-redux.d.ts b/react-redux/react-redux.d.ts new file mode 100644 index 0000000000..9c46fd10c7 --- /dev/null +++ b/react-redux/react-redux.d.ts @@ -0,0 +1,68 @@ +// Type definitions for react-redux 4.4.0 +// Project: https://github.com/rackt/react-redux +// Definitions by: Qubo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// +/// + +declare module "react-redux" { + import { ComponentClass, Component, StatelessComponent } from 'react'; + import { Store, Dispatch, ActionCreator } from 'redux'; + + export interface ComponentConstructDecorator

{ + |StatelessComponent

)>(component: TComponentConstruct): TComponentConstruct + } + + /** + * Connects a React component to a Redux store. + * @param mapStateToProps + * @param mapDispatchToProps + * @param mergeProps + * @param options + */ + export function connect

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

; + + interface MapStateToProps { + (state: any, ownProps?: any): any; + } + + interface MapDispatchToPropsFunction { + (dispatch: Dispatch, ownProps?: any): any; + } + + interface MapDispatchToPropsObject { + [name: string]: ActionCreator; + } + + interface MergeProps { + (stateProps: any, dispatchProps: any, ownProps: any): any; + } + + interface Options { + /** + * If true, implements shouldComponentUpdate and shallowly compares the result of mergeProps, + * preventing unnecessary updates, assuming that the component is a “pure” component + * and does not rely on any input or state other than its props and the selected Redux store’s state. + * Defaults to true. + * @default true + */ + pure: boolean; + } + + export interface Property { + /** + * The single Redux store in your application. + */ + store?: Store; + children?: Function; + } + + /** + * Makes the Redux store available to the connect() calls in the component hierarchy below. + */ + export class Provider extends Component { } +}