Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Improved typing #241

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 25 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -594,12 +594,10 @@ Components are often data-agnostic, and work mostly at a presentational level.
You can read more about this concept on [Dan Abramov's article *Presentational and Container Components*](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0).

First let's update `src/components/Hello.tsx` so that it can modify state.
We'll add two optional callback properties to `Props` named `onIncrement` and `onDecrement`:
We'll create the `DispatchProps` interface that holds two optional callback properties named `onIncrement` and `onDecrement`:

```ts
export interface Props {
name: string;
enthusiasmLevel?: number;
export interface DispatchProps {
onIncrement?: () => void;
onDecrement?: () => void;
}
Expand All @@ -608,22 +606,25 @@ export interface Props {
Then we'll bind those callbacks to two new buttons that we'll add into our component.

```ts
function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) {
if (enthusiasmLevel <= 0) {
throw new Error('You could be a little more enthusiastic. :D');
}
export class Hello extends React.Component<Props & DispatchProps, object> {
render() {
const {enthusiasmLevel = 1} = this.props;
if (enthusiasmLevel <= 0) {
throw new Error('You could be a little more enthusiastic. :D');
}

return (
<div className="hello">
<div className="greeting">
Hello {name + getExclamationMarks(enthusiasmLevel)}
</div>
<div>
<button onClick={onDecrement}>-</button>
<button onClick={onIncrement}>+</button>
return (
<div className="hello">
<div className="greeting">
Hello {this.props.name + getExclamationMarks(enthusiasmLevel)}
</div>
<div>
<button onClick={this.props.onDecrement}>-</button>
<button onClick={this.props.onIncrement}>+</button>
</div>
</div>
</div>
);
);
}
}
```

Expand All @@ -634,7 +635,7 @@ Now that our component is updated, we're ready to wrap it into a container.
Let's create a file named `src/containers/Hello.tsx` and start off with the following imports.

```ts
import Hello from '../components/Hello';
import { Hello, Props, DispatchProps } from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';
Expand All @@ -652,7 +653,7 @@ Our `Hello` component, on the other hand, expected a `name` and an `enthusiasmLe
Let's go ahead and write that.

```ts
export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState): Props {
return {
enthusiasmLevel,
name: languageName,
Expand All @@ -666,7 +667,7 @@ Namely, we still want to pass in the `onIncrement` and `onDecrement` callbacks.
This dispatcher function can pass actions into our store to make updates, so we can create a pair of callbacks that will call the dispatcher as necessary.

```ts
export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>): DispatchProps {
return {
onIncrement: () => dispatch(actions.incrementEnthusiasm()),
onDecrement: () => dispatch(actions.decrementEnthusiasm()),
Expand All @@ -687,19 +688,19 @@ When we're finished, our file should look like this:
```ts
// src/containers/Hello.tsx

import Hello from '../components/Hello';
import { Hello, Props, DispatchProps } from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState): Props {
return {
enthusiasmLevel,
name: languageName,
}
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>): DispatchProps {
return {
onIncrement: () => dispatch(actions.incrementEnthusiasm()),
onDecrement: () => dispatch(actions.decrementEnthusiasm()),
Expand Down
38 changes: 22 additions & 16 deletions src/components/Hello.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,32 @@ import './Hello.css';
export interface Props {
name: string;
enthusiasmLevel?: number;
onIncrement?: () => void;
onDecrement?: () => void;
}

export interface DispatchProps {
onDecrement?: () => object;
onIncrement?: () => object;
}

function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) {
if (enthusiasmLevel <= 0) {
throw new Error('You could be a little more enthusiastic. :D');
}
export class Hello extends React.Component<Props & DispatchProps, object> {
render() {
const {enthusiasmLevel = 1} = this.props;
if (enthusiasmLevel <= 0) {
throw new Error('You could be a little more enthusiastic. :D');
}

return (
<div className="hello">
<div className="greeting">
Hello {name + getExclamationMarks(enthusiasmLevel)}
return (
<div className="hello">
<div className="greeting">
Hello {this.props.name + getExclamationMarks(enthusiasmLevel)}
</div>
<div>
<button onClick={this.props.onDecrement}>-</button>
<button onClick={this.props.onIncrement}>+</button>
</div>
</div>
<div>
<button onClick={onDecrement}>-</button>
<button onClick={onIncrement}>+</button>
</div>
</div>
);
);
}
}

export default Hello;
Expand Down
6 changes: 3 additions & 3 deletions src/containers/Hello.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import Hello from '../components/Hello';
import { Hello, Props, DispatchProps } from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
function mapStateToProps({ enthusiasmLevel, languageName }: StoreState): Props {
return {
enthusiasmLevel,
name: languageName,
};
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>): DispatchProps {
return {
onIncrement: () => dispatch(actions.incrementEnthusiasm()),
onDecrement: () => dispatch(actions.decrementEnthusiasm()),
Expand Down