Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bdec1e5
Updated tests to fix build Closed #95 (#133)
piotrwitek Feb 3, 2019
857d9fd
Adds info import module decleration (#134)
arshadkazmi42 Feb 4, 2019
23ffca5
Updated Recipes section Closed #137
piotrwitek Feb 12, 2019
8f51601
Updated TOC
piotrwitek Feb 12, 2019
af7d940
Updated deps (#139)
piotrwitek Feb 12, 2019
c06d37a
Added example for using context in class component (#141)
binoy14 Feb 14, 2019
33d96b6
Testing epics (#144)
piotrwitek Feb 22, 2019
8c796de
updated deps
piotrwitek Mar 7, 2019
1259b21
added redux-thunk types overload
piotrwitek Mar 7, 2019
d0a05b2
Updated legacy patterns
piotrwitek Mar 7, 2019
5d03b97
ThunkActionType prototype
piotrwitek Mar 7, 2019
342a6ad
fix spelling mistake (#152)
SCKelemen Apr 6, 2019
0ecf245
Updated docs and and example of integration with redux-thunk Resolved…
piotrwitek Apr 6, 2019
c8d35fe
Merge branch 'redux-thunk'
piotrwitek Apr 6, 2019
b5cefb4
Added hyperlinks for better UX
piotrwitek Apr 6, 2019
34fc808
Small updates
piotrwitek Apr 13, 2019
e732b43
Updated playground project and added integration with react-redux-typ…
piotrwitek Apr 13, 2019
3f978be
Added new solution to Connect with `react-redux` to solve validation …
piotrwitek Apr 13, 2019
acd9b20
Added ESLint config section (#158)
piotrwitek Apr 14, 2019
93fc2b8
Refactored playground to use create-react-app (#159)
piotrwitek Apr 14, 2019
cf8a03c
Capitalize file to fix import on POSIX systems (#160)
lordi Apr 15, 2019
05ddc8f
Added prettier to common npm scripts
piotrwitek Apr 18, 2019
0ff885d
Added doctoc
piotrwitek Apr 21, 2019
01bc1df
Updated readme
piotrwitek Apr 21, 2019
0c2afc9
Updated readme with new section about createReducer API
piotrwitek Apr 22, 2019
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
Prev Previous commit
Next Next commit
Updated Recipes section Closed piotrwitek#137
  • Loading branch information
piotrwitek committed Feb 12, 2019
commit 23ffca58c315ecfcf57ca0570ccccd3711798bb0
173 changes: 97 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ _"This guide is a **living compendium** documenting the most important patterns
### Playground Project
[![Build Status](https://semaphoreci.com/api/v1/piotrekwitek/react-redux-typescript-guide/branches/master/shields_badge.svg)](https://semaphoreci.com/piotrekwitek/react-redux-typescript-guide)

You should check out Playground Project located in the `/playground` folder. It is a source of all the code examples found in the guide. They are all tested with the most recent version of TypeScript and 3rd party type definitions (like `@types/react` or `@types/react-redux`) to ensure the examples are up-to-date and not broken with updated definitions.
You should check out Playground Project located in the `/playground` folder. It is a source of all the code examples found in the guide. They are all tested with the most recent version of TypeScript and 3rd party type-definitions (like `@types/react` or `@types/react-redux`) to ensure the examples are up-to-date and not broken with updated definitions.
> Playground was created in such a way that you can simply clone the repository locally and immediately play around on your own. It will help you to learn all the examples from this guide in a real project environment without the need to create some complicated environment setup by yourself.

## Contributing Guide
Expand Down Expand Up @@ -67,12 +67,11 @@ Issues can be funded by anyone and the money will be transparently distributed t
- [Common Npm Scripts](#common-npm-scripts)
- [Recipes](#recipes)
- [Baseline tsconfig.json](#baseline-tsconfigjson)
- [Default and Named Module Exports](#default-and-named-module-exports)
- [Imports in Module Decleration](#imports-in-module-decleration)
- [Type Augmentation for npm libraries](#type-augmentation-for-npm-libraries)
- [Override type-definitions for npm libraries](#override-type-definitions-for-npm-libraries)
- [Ambient Modules Tips](#ambient-modules-tips)
- [Type-Definitions Tips](#type-definitions-tips)
- [Type Augmentation Tips](#type-augmentation-tips)
- [FAQ](#faq)
- [Tutorials](#tutorials)
- [Tutorials & Articles](#tutorials--articles)
- [Contributors](#contributors)

---
Expand Down Expand Up @@ -1524,6 +1523,7 @@ Object.values = () => [];
# Recipes

### Baseline tsconfig.json

- Recommended baseline config carefully optimized for strict type-checking and optimal webpack workflow
- Install [`tslib`](https://www.npmjs.com/package/tslib) to cut on bundle size, by using external runtime helpers instead of adding them inline: `npm i tslib`
- Example "paths" setup for baseUrl relative imports with Webpack
Expand Down Expand Up @@ -1572,18 +1572,33 @@ Object.values = () => [];

[⇧ back to top](#table-of-contents)

### Default and Named Module Exports
> Most flexible solution is to use module folder pattern, because you can leverage both named and default import when you see fit.
Using this solution you'll achieve better encapsulation for internal structure/naming refactoring without breaking your consumer code:
### General Tips

#### - should I still use React.PropTypes in TS?
No. With TypeScript, using PropTypes is an unnecessary overhead. When declaring Props and State interfaces, you will get complete intellisense and design-time safety with static type checking. This way you'll be safe from runtime errors and you will save a lot of time on debugging. Additional benefit is an elegant and standardized method of documenting your component public API in the source code.

[⇧ back to top](#table-of-contents)

#### - when to use `interface` declarations and when `type` aliases?
From practical side, using `interface` declaration will create an identity (interface name) in compiler errors, on the contrary `type` aliases doesn't create an identity and will be unwinded to show all the properties and nested types it consists of.
Although I prefer to use `type` most of the time there are some places this can become too noisy when reading compiler errors and that's why I like to leverage this distinction to hide some of not so important type details in errors using interfaces identity.
Related `ts-lint` rule: https://palantir.github.io/tslint/rules/interface-over-type-literal/

[⇧ back to top](#table-of-contents)

#### - what's better default or named exports?
A common flexible solution is to use module folder pattern, because you can leverage both named and default import when you see fit.
With this solution you'll achieve better encapsulation and be able to safely refactor internal naming and folders structure without breaking your consumer code:

```ts
// 1. in `components/` folder create component file (`select.tsx`) with default export:
// 1. create your component files (`select.tsx`) using default export in some folder:

// components/select.tsx
const Select: React.FC<Props> = (props) => {
...
export default Select;

// 2. in `components/` folder create `index.ts` file handling named imports:
// 2. in this folder create an `index.ts` file that will re-export components with named exports:

// components/index.ts
export { default as Select } from './select';
Expand All @@ -1600,32 +1615,45 @@ import Select from '@src/components/select';

[⇧ back to top](#table-of-contents)

### Imports in Module Decleration
> When creating 3rd party modules declarations all the imports should be put inside the module decleration, otherwise it will be treated as augmentation and show error
```ts
declare module "react-custom-scrollbars" {
import * as React from "react";
export interface positionValues {
...
#### - how to best initialize class instance or static properties?
Prefered modern syntax is to use class Property Initializers
```tsx
class ClassCounterWithInitialCount extends React.Component<Props, State> {
// default props using Property Initializers
static defaultProps: DefaultProps = {
className: 'default-class',
initialCount: 0,
};

// initial state using Property Initializers
state: State = {
count: this.props.initialCount,
};
...
}
```
[⇧ back to top](#table-of-contents)

### Type Augmentation for npm libraries
Strategies to fix issues coming from external type-definitions files (*.d.ts)
[⇧ back to top](#table-of-contents)

#### Augmenting library internal definitions - using relative import resolution
```ts
// added missing autoFocus Prop on Input component in "[email protected]" npm package
declare module '../node_modules/antd/lib/input/Input' {
export interface InputProps {
autoFocus?: boolean;
}
#### - how to best declare component handler functions?
Prefered modern syntax is to use Class Fields with arrow functions
```tsx
class ClassCounter extends React.Component<Props, State> {
// handlers using Class Fields with arrow functions
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
...
}
```

#### Augmenting library public definitions - using node module import resolution
[⇧ back to top](#table-of-contents)

### Ambient Modules Tips

#### Imports in ambient modules
For type augmentation imports should stay outside of module declaration.
```ts
// fixed broken public type declaration in "[email protected]" npm package
import { Operator } from 'rxjs/Operator';
import { Observable } from 'rxjs/Observable';

Expand All @@ -1636,7 +1664,21 @@ declare module 'rxjs/Subject' {
}
```

#### To quick-fix missing type-definitions for vendor modules you can "assert" a module type with `any` using [Shorthand Ambient Modules](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#shorthand-ambient-modules)
When creating 3rd party type-definitions all the imports should be kept inside the module decleration, otherwise it will be treated as augmentation and show error

```ts
declare module "react-custom-scrollbars" {
import * as React from "react";
export interface positionValues {
...
```

[⇧ back to top](#table-of-contents)

### Type-Definitions Tips

#### Missing type-definitions error
if you cannot find types for a third-party module you can provide your own types or disable type-checking for this module using [Shorthand Ambient Modules](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#shorthand-ambient-modules)

```tsx
// typings/modules.d.ts
Expand All @@ -1645,12 +1687,8 @@ declare module 'react-test-renderer';

```

> More advanced scenarios for working with vendor type-definitions can be found here [Official TypeScript Docs](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#working-with-other-javascript-libraries)

[⇧ back to top](#table-of-contents)

### Override type-definitions for npm libraries
If you want to use an alternative (customized) type-definitions for some npm library (that usually comes with it's own type definitions), you can do it by adding an override in `paths` compiler option.
#### Using custom `d.ts` files for npm modules
If you want to use an alternative (customized) type-definitions for some npm module (that usually comes with it's own type-definitions), you can do it by adding an override in `paths` compiler option.

```ts
{
Expand All @@ -1667,58 +1705,41 @@ If you want to use an alternative (customized) type-definitions for some npm lib

[⇧ back to top](#table-of-contents)

---

# FAQ

### - should I still use React.PropTypes in TS?
> No. With TypeScript, using PropTypes is an unnecessary overhead. When declaring IProps and IState interfaces, you will get complete intellisense and compile-time safety with static type checking. This way you'll be safe from runtime errors and you will save a lot of time on debugging. Additional benefit is an elegant and standardized method of documenting your component external API in the source code.

[⇧ back to top](#table-of-contents)

### - when to use `interface` declarations and when `type` aliases?
> From practical side, using `interface` declaration will display identity (interface name) in compiler errors, on the contrary `type` aliases will be unwinded to show all the properties and nested types it consists of. This can be a bit noisy when reading compiler errors and I like to leverage this distinction to hide some of not so important type details in errors
Related `ts-lint` rule: https://palantir.github.io/tslint/rules/interface-over-type-literal/
### Type Augmentation Tips
Strategies to fix issues coming from external type-definitions files (*.d.ts)

[⇧ back to top](#table-of-contents)
#### Augmenting library internal declarations - using relative import

### - how to best initialize class instance or static properties?
> Prefered modern style is to use class Property Initializers
```tsx
class ClassCounterWithInitialCount extends React.Component<Props, State> {
// default props using Property Initializers
static defaultProps: DefaultProps = {
className: 'default-class',
initialCount: 0,
};

// initial state using Property Initializers
state: State = {
count: this.props.initialCount,
};
...
```ts
// added missing autoFocus Prop on Input component in "[email protected]" npm package
declare module '../node_modules/antd/lib/input/Input' {
export interface InputProps {
autoFocus?: boolean;
}
}
```

[⇧ back to top](#table-of-contents)
#### Augmenting library public declarations - using node_modules import

### - how to best declare component handler functions?
> Prefered modern style is to use Class Fields with arrow functions
```tsx
class ClassCounter extends React.Component<Props, State> {
// handlers using Class Fields with arrow functions
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
...
```ts
// fixed broken public type-definitions in "[email protected]" npm package
import { Operator } from 'rxjs/Operator';
import { Observable } from 'rxjs/Observable';

declare module 'rxjs/Subject' {
interface Subject<T> {
lift<R>(operator: Operator<T, R>): Observable<R>;
}
}
```

> More advanced scenarios for working with vendor type-definitions can be found here [Official TypeScript Docs](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#working-with-other-javascript-libraries)

[⇧ back to top](#table-of-contents)

---

## Tutorials
## Tutorials & Articles
> Curated list of relevant in-depth tutorials

Higher-Order Components:
Expand Down
Loading