Skip to content

Commit

Permalink
Merge pull request reduxjs#1 from aikoven/next
Browse files Browse the repository at this point in the history
Add tests for TS definitions
  • Loading branch information
bbenezech authored Dec 1, 2016
2 parents 14acd15 + f695975 commit 303b7fe
Show file tree
Hide file tree
Showing 5 changed files with 340 additions and 4 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ node_js:
script:
- npm run lint
- npm run test:cov
- npm run test:typescript
after_success:
- npm run coverage
8 changes: 4 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ interface ComponentDecorator<TOriginalProps, TOwnProps> {
* - TStateProps: Result of MapStateToProps
* - TDispatchProps: Result of MapDispatchToProps
*/
function connect<State, TOwnProps>(): ComponentDecorator<{ dispatch: Dispatch<State> } & TOwnProps, TOwnProps>;
export function connect<State, TOwnProps>(): ComponentDecorator<{ dispatch: Dispatch<State> } & TOwnProps, TOwnProps>;

function connect<State, TOwnProps, TStateProps>(
export function connect<State, TOwnProps, TStateProps>(
mapStateToProps: FuncOrSelf<MapStateToProps<State, TOwnProps, TStateProps>>,
): ComponentDecorator<TStateProps & { dispatch: Dispatch<State> } & TOwnProps, TOwnProps>;

function connect<State, TOwnProps, TStateProps, TDispatchProps>(
export function connect<State, TOwnProps, TStateProps, TDispatchProps>(
mapStateToProps: FuncOrSelf<MapStateToProps<State, TOwnProps, TStateProps>>|null,
mapDispatchToProps: FuncOrSelf<MapDispatchToPropsFunction<State, TOwnProps, TDispatchProps> | MapDispatchToPropsObject & TDispatchProps>
): ComponentDecorator<TStateProps & TDispatchProps & TOwnProps, TOwnProps>;

function connect<State, TOwnProps, TStateProps, TDispatchProps, TMergeProps>(
export function connect<State, TOwnProps, TStateProps, TDispatchProps, TMergeProps>(
mapStateToProps: FuncOrSelf<MapStateToProps<State, TOwnProps, TStateProps>>|null,
mapDispatchToProps: FuncOrSelf<MapDispatchToPropsFunction<State, TOwnProps, TDispatchProps>| MapDispatchToPropsObject & TDispatchProps>,
mergeProps: MergeProps<TOwnProps, TStateProps, TDispatchProps, TMergeProps>,
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"test": "cross-env BABEL_ENV=commonjs NODE_ENV=test mocha --compilers js:babel-register --recursive --require ./test/setup.js",
"test:watch": "npm test -- --watch",
"test:cov": "cross-env NODE_ENV=test nyc npm test",
"test:typescript": "typings-tester --dir test/typescript",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov"
},
"repository": {
Expand Down Expand Up @@ -49,6 +50,7 @@
},
"homepage": "/~https://github.com/gaearon/react-redux",
"devDependencies": {
"@types/react": "^0.14.49",
"babel-cli": "^6.3.17",
"babel-core": "^6.3.26",
"babel-eslint": "^6.1.2",
Expand Down Expand Up @@ -95,6 +97,8 @@
"react-dom": "^0.14.0",
"redux": "^3.0.0",
"rimraf": "^2.3.4",
"typescript": "^2.0.10",
"typings-tester": "^0.2.0",
"webpack": "^1.11.0"
},
"dependencies": {
Expand Down
323 changes: 323 additions & 0 deletions test/typescript/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
import {Dispatch, Store} from "redux";
import {connect, Provider} from "../../index";


function testNoArgs() {
const Connected = connect()(props => {
// typings:expect-error
props.foo;

return <button onClick={() => props.dispatch({type: 'CLICKED'})}/>;
});

// typings:expect-error
const c = <Connected foo="foo"/>;

const ConnectedWithProps = connect<{}, {foo: string}>()(props => {
props.foo;
return <button onClick={() => props.dispatch({type: 'CLICKED'})}/>;
});

const cp = <ConnectedWithProps foo="foo"/>;

const connectorWithProps = connect<{}, {foo: string}>();

// typings:expect-error
connectorWithProps((props: {bar: string}) => <div/>);
}


function testMapState() {
type MyState = {foo: string, bar: number};

// typings:expect-error
connect<MyState, {}, {}>((state: {baz: boolean}) => ({}));

const Connected = connect(
(state: MyState, props: {baz: boolean}) => {
return {
foo: state.foo,
fizz: props.baz,
};
},
)(props => {
const foo: string = props.foo;
const baz: boolean = props.baz;
const fizz: boolean = props.fizz;

// typings:expect-error
props.bar;

props.dispatch({type: 'ACTION'});

return <div/>;
});

// typings:expect-error
<Connected/>;

<Connected baz/>;

// typings:expect-error
<Connected baz="baz"/>;

const Connected2 = connect<MyState, {baz: boolean}, {foo: string, fizz: boolean}>(
() => (state: MyState, props: {baz: boolean}) => {
return {
foo: state.foo,
fizz: props.baz,
};
}
)(props => {
const foo: string = props.foo;
const baz: boolean = props.baz;
const fizz: boolean = props.fizz;

// typings:expect-error
props.bar;

props.dispatch({type: 'ACTION'});

return <div/>;
});

// typings:expect-error
<Connected2/>;

<Connected2 baz/>;

// typings:expect-error
<Connected2 baz="baz"/>;
}


function testMapDispatch() {
type MyState = {foo: string};

const Connected = connect(
(state: MyState) => {
return {
foo: state.foo,
};
},
(dispatch: Dispatch<MyState>) => {
return {
handleClick() {
dispatch({type: 'CLICKED'});
},
};
},
)(props => {
const foo: string = props.foo;
// typings:expect-error
props.bar;

// typings:expect-error
props.dispatch({type: 'TYPE'});

return <button onClick={props.handleClick}/>;
});

<Connected/>;
// typings:expect-error
<Connected bar={42}/>;

type Props = {bar: number};
const ConnectedWithProps = connect(
(state: MyState) => {
return {foo: state.foo};
},
(dispatch: Dispatch<MyState>, props: Props) => {
return {
handleClick() {
dispatch({type: 'CLICKED', bar: props.bar});
},
};
},
)(props => {
const foo: string = props.foo;
const bar: number = props.bar;

// typings:expect-error
props.dispatch({type: 'TYPE'});

return <button onClick={props.handleClick}/>;
});

// typings:expect-error
<ConnectedWithProps/>;

<ConnectedWithProps bar={42}/>;

const ConnectedWithDispatchObject = connect(
(state: MyState) => {
return {foo: state.foo};
},
{
handleClick() {
return {type: 'CLICKED'};
},
},
)(props => {
const foo: string = props.foo;
// typings:expect-error
props.bar;

// typings:expect-error
props.dispatch({type: 'TYPE'});

return <button onClick={props.handleClick}/>;
});

// typings:expect-error
connect(
null,
{
handleClick: () => 'not-an-action',
},
);

connect(
null,
{
handleClick: () => (dispatch: Dispatch<MyState>) => {
dispatch({type: 'SOME_ACTION'});
},
},
);
}


function testMergeProps() {
type MyState = {foo: string};

const connector = connect(
(state: MyState) => {
return {foo: state.foo};
},
(dispatch: Dispatch<MyState>) => {
return {
handleClick() {
dispatch({type: 'CLICKED'});
},
};
},
(stateProps, dispatchProps) => {
// typings:expect-error
stateProps.bar;
// typings:expect-error
dispatchProps.foo;

return {stateProps, dispatchProps};
}
);

// typings:expect-error
connector((props: {bar: number}) => <div/>);

const Connected = connector(props => {
// typings:expect-error
props.foo;
// typings:expect-error
props.handleClick;

const foo: string = props.stateProps.foo;

return <button onClick={props.dispatchProps.handleClick}/>;
});

// typings:expect-error
<Connected foo="fizz"/>;

<Connected/>;

type MyProps = {bar: number};

const Connected2 = connect(
(state: MyState, props: MyProps) => {
return {
foo: state.foo,
baz: props.bar,
};
},
(dispatch: Dispatch<MyState>, props: MyProps) => {
// typings:expect-error
props.foo;

return {
handleClick() {
dispatch({type: 'CLICKED', bar: props.bar});
},
};
},
(stateProps, dispatchProps, ownProps) => {
// typings:expect-error
stateProps.bar;
// typings:expect-error
dispatchProps.bar;
// typings:expect-error
ownProps.foo;

return {
fizz: stateProps.foo,
bazz: stateProps.baz,
buzz: ownProps.bar,
clickHandler: dispatchProps.handleClick,
}
}
)(props => {
// typings:expect-error
props.foo;
// typings:expect-error
props.baz;
// typings:expect-error
props.bar;
// typings:expect-error
props.handleClick;

const fizz: string = props.fizz;
const bazz: number = props.bazz;
const buzz: number = props.buzz;

return <button onClick={props.clickHandler}/>;
});

// typings:expect-error
<Connected2 foo="foo"/>;
// typings:expect-error
<Connected2 handleClick={() => {}}/>;
// typings:expect-error
<Connected2/>;

<Connected2 bar={1}/>;
}

function testOptions() {
// typings:expect-error
connect(null, null, null, {pure: 1});
// typings:expect-error
connect(null, null, null, {withRef: 1});

connect(null, null, null, {pure: true});
connect(null, null, null, {withRef: true});
connect(null, null, null, {pure: true, withRef: true});

connect(
(state: {foo: string}) => ({foo: state.foo}),
null,
null,
{pure: true}
);
}

function testProvider() {
// typings:expect-error
<Provider/>;
// typings:expect-error
<Provider store=""/>;
// typings:expect-error
<Provider store={null}/>;

let store: Store<{}> = {} as Store<{}>;
<Provider store={store}/>;
}
8 changes: 8 additions & 0 deletions test/typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
"jsx": "react",
"noImplicitAny": true,
"strictNullChecks": true
}
}

0 comments on commit 303b7fe

Please sign in to comment.