Skip to content

Commit 8cf568e

Browse files
committed
updated guide
1 parent c51eb04 commit 8cf568e

File tree

1 file changed

+52
-57
lines changed

1 file changed

+52
-57
lines changed

README.md

Lines changed: 52 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ A comprehensive guide to static typing "React & Redux" apps using TypeScript.
1111

1212
### Table of Contents
1313
- [React](#react)
14-
- [Class Component](#class-component)
1514
- [Stateless Component](#stateless-component)
15+
- [Class Component](#class-component)
1616
- [Higher-Order Component](#higher-order-component)
1717
- [Redux Connected Component](#redux-connected-component)
1818
- [Redux](#redux)
@@ -39,6 +39,30 @@ A comprehensive guide to static typing "React & Redux" apps using TypeScript.
3939

4040
---
4141

42+
## Stateless Component
43+
- stateless component boilerplate
44+
```tsx
45+
import * as React from 'react';
46+
47+
type Props = {
48+
className?: string,
49+
style?: React.CSSProperties,
50+
};
51+
52+
const MyComponent: React.StatelessComponent<Props> = (props) => {
53+
const { children, ...restProps } = props;
54+
return (
55+
<div {...restProps} >
56+
{children}
57+
</div>
58+
);
59+
};
60+
61+
export default MyComponent;
62+
```
63+
64+
---
65+
4266
## Class Component
4367
- class component boilerplate
4468
```tsx
@@ -51,65 +75,41 @@ type Props = {
5175
};
5276

5377
type State = {
54-
count: number,
78+
counter: number,
5579
};
5680

5781
class MyComponent extends React.Component<Props, State> {
5882
// default props using Property Initializers
59-
static defaultProps: Props = {
83+
static defaultProps: Partial<Props> = {
6084
className: 'default-class',
61-
initialCount: 0,
6285
};
63-
86+
6487
// initial state using Property Initializers
6588
state: State = {
66-
count: this.props.initialCount,
89+
counter: this.props.initialCount || 0,
6790
};
68-
69-
// handlers using Class Fields with arrow functions
70-
handleClick = () => this.setState({ count: this.state.count + 1});
71-
91+
7292
// lifecycle methods should be declared as normal instance methods and it's fine
7393
componentDidMount() {
94+
// tslint:disable-next-line:no-console
7495
console.log('Mounted!');
7596
}
76-
97+
98+
// handlers using Class Fields with arrow functions
99+
increaseCounter = () => { this.setState({ counter: this.state.counter + 1 }); };
100+
77101
render() {
78102
const { children, initialCount, ...restProps } = this.props;
79-
103+
80104
return (
81-
<div {...restProps} onClick={this.handleClick} >
82-
Clicks: {this.state.count}
105+
<div {...restProps} onClick={this.increaseCounter} >
106+
Clicks: {this.state.counter}
83107
<hr />
84108
{children}
85109
</div>
86110
);
87111
}
88-
};
89-
90-
export default MyComponent;
91-
```
92-
93-
---
94-
95-
## Stateless Component
96-
- stateless component boilerplate
97-
```tsx
98-
import * as React from 'react';
99-
100-
type Props = {
101-
className?: string,
102-
style?: React.CSSProperties,
103-
};
104-
105-
const MyComponent: React.StatelessComponent<Props> = (props) => {
106-
const { children, ...restProps } = props;
107-
return (
108-
<div {...restProps} >
109-
{children}
110-
</div>
111-
);
112-
};
112+
}
113113

114114
export default MyComponent;
115115
```
@@ -812,19 +812,14 @@ declare module '../node_modules/antd/lib/button/Button' {
812812
// react
813813
npm i -D @types/react @types/react-dom @types/react-redux
814814

815-
// redux has types included in it's npm package, no need to use @types
815+
// redux has types included in it's npm package - don't install from @types
816816
```
817817
818-
### - when to use `interface` and when `type` to behave consistently?
819-
> Use `type` when declaring simple object literal structs e.g. Component Props, Component State, Redux State, Redux Action.
820-
In other cases it's more flexible to use `interface` over `type` because interfaces can be implemented, extended and merged.
821-
Related `ts-lint` rule: https://palantir.github.io/tslint/rules/interface-over-type-literal/
822-
823-
### - should I use React.PropTypes?
824-
> No. In TypeScript it is completely unnecessary, you will get a much better free type checking and intellisense at compile time when declaring a "generic type" for component: `React.Component<{ myProp: string }, { myState: number}>`, this way you'll never get any runtime errors and get elegant way of describing component external API.
818+
### - should I still use React.PropTypes in TS?
819+
> No. In TypeScript it is unnecessary, when declaring Props and State types (refer to React components examples) you will get completely free intellisense and compile-time safety with static type checking, this way you'll be safe from runtime errors, not waste time on debugging and get an elegant way of describing component external API in your source code.
825820
826-
### - how to best declare component instance properties?
827-
> Don't use old-school React class constructors way, prefer to use Property Initializers (first class support in TypeScript).
821+
### - how to best initialize class instance or static properties?
822+
> Prefered modern style is to use class Property Initializers
828823
```tsx
829824
class MyComponent extends React.Component<Props, State> {
830825
// default props using Property Initializers
@@ -835,26 +830,26 @@ class MyComponent extends React.Component<Props, State> {
835830

836831
// initial state using Property Initializers
837832
state: State = {
838-
count: this.props.initialCount,
833+
counter: this.props.initialCount,
839834
};
840835
...
841836
}
842837
```
843838
844839
### - how to best declare component handler functions?
845-
> Don't use old-school class methods and function bind way, prefer to use Class Fields with arrow functions (first class support in TypeScript)
840+
> Prefered modern style is to use Class Fields with arrow functions
846841
```tsx
847842
class MyComponent extends React.Component<Props, State> {
848843
// handlers using Class Fields with arrow functions
849-
handleClick = () => this.setState({ count: this.state.count + 1});
850-
851-
// an exception are lifecycle methods should be declared as normal instance methods and it's fine, because we are extending React Component
852-
componentDidMount() {
853-
console.log('Mounted!');
854-
}
844+
increaseCounter = () => { this.setState({ counter: this.state.counter + 1}); };
855845
...
856846
}
857847
```
848+
849+
### - is it better to use `interface` or `type` as convention?
850+
> In general this is a matter of taste, you can extend and implement type the same as an interface. The only major difference is that you will get a compiler error when extending and interface with incompatible properties, in contrary to merging types (&) operation, but otherwise they are synonymous.
851+
Related `ts-lint` rule: https://palantir.github.io/tslint/rules/interface-over-type-literal/
852+
858853
---
859854
860855
# Project Examples

0 commit comments

Comments
 (0)