You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+77-1Lines changed: 77 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@
6
6
### Goals
7
7
- Complete type safety with [`--strict`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) flag without failing to `any` type for the best static-typing experience
8
8
- Minimize amount of manually writing type declarations by leveraging [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html)
9
-
- Reduce redux boilerplate and complexity of it's type annotations to a minimum with [simple utility functions](https://github.com/piotrwitek/react-redux-typescript) by extensive use of[Generics](https://www.typescriptlang.org/docs/handbook/generics.html) and [Advanced Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html) features
9
+
- Reduce redux boilerplate code with [simple utility functions](https://github.com/piotrwitek/typesafe-actions) using[Generics](https://www.typescriptlang.org/docs/handbook/generics.html) and [Advanced Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html) features
10
10
11
11
### Playground Project
12
12
You should check 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.
@@ -618,6 +618,82 @@ export default () => (
618
618
619
619
[⇧ back to top](#table-of-contents)
620
620
621
+
## Higher-Order Components
622
+
- function that takes a component and returns a new component
623
+
- a new component will infer Props interface from wrapped Component extended with Props of HOC
624
+
- will filter out props specific to HOC, and the rest will be passed through to wrapped component
**If you try to use `connect` or `bindActionCreators` explicitly and type your component callback props as `() => void` this will raise compiler errors because `bindActionCreators` typings will not map your action creator type correctly due to current TypeScript limitations.**
3
+
4
+
As a decent alternative I'm recommending to use `() => any` type instead, it will work just fine in all scenarios and should not cause any type errors in all possible scenarios.
5
+
6
+
> All the code examples in the Guide using `connect` are also using this pattern, if there is any progress in TypeScript Language that will fix this I'll update the guide and make a big announcement on my twitter/medium. (There are a few proposals already)
7
+
8
+
> There is also a way to retain type soundness but it will involve an explicit wrapping with `dispatch` and will be very tedious for the long term, see example:
This pattern is focused on a KISS principle - to stay clear of complex proprietary abstractions and follow simple and familiar JavaScript const based types:
5
+
> Using Typesafe Action Creators for Redux [`typesafe-actions`](https://github.com/piotrwitek/typesafe-actions)
7
6
8
-
Advantages:
9
-
- simple "const" based types
10
-
- familiar to standard JS usage
11
-
12
-
Disadvantages:
13
-
- significant amount of boilerplate and duplication
14
-
- necessary to export both action types and action creators to re-use in other places, e.g. `redux-saga` or `redux-observable`
7
+
A recommended approach is to use a simple factory function to automate the creation of type-safe action creators. The advantage is that we can reduce a lot of code repetition and also minimize surface of errors by using type-checked API.
8
+
> There are more functional helpers available that will help you to further reduce tedious boilerplate and type-annotations in common scenarios like reducers (`getType`) or epics (`isActionOf`). All that without losing type-safety! Please check very short [Tutorial](https://github.com/piotrwitek/typesafe-actions#tutorial)
In a DRY approach, we're introducing a simple factory function to automate the creation process of type-safe action creators. The advantage here is that we can reduce boilerplate and repetition significantly. It is also easier to re-use action creators in other layers thanks to `getType` helper function returning "type constant".
23
-
24
-
Advantages:
25
-
- using factory function to automate creation of type-safe action creators
26
-
- less boilerplate and code repetition than KISS Style
27
-
- getType helper to obtain action creator type (this makes using "type constants" unnecessary)
-[Discriminated Union types](https://www.typescriptlang.org/docs/handbook/advanced-types.html)
60
20
-[Mapped types](https://www.typescriptlang.org/docs/handbook/advanced-types.html) e.g. `Readonly` & `Partial`
61
21
62
-
### Tutorial
63
-
Declare reducer `State` type definition with readonly modifier for `type level` immutability
22
+
### State with Type-level Immutability
23
+
Declare reducer `State` type with `readonly` modifier for "type level" immutability
64
24
```ts
65
25
exporttypeState= {
66
26
readonly counter:number,
67
27
};
68
28
```
69
29
70
-
Readonly modifier allow initialization, but will not allow rassignment highlighting an error
30
+
Readonly modifier allow initialization, but will not allow rassignment by highlighting a compiler error
71
31
```ts
72
32
exportconst initialState:State= {
73
33
counter: 0,
@@ -76,69 +36,50 @@ export const initialState: State = {
76
36
initialState.counter=3; // Error, cannot be mutated
77
37
```
78
38
79
-
#### Caveat: Readonly does not provide recursive immutability on objects
80
-
> This means that readonly modifier does not propagate immutability on nested properties of objects or arrays of objects. You'll need to set it explicitly on each nested property.
39
+
#### Caveat: Readonly does not provide a recursive immutability on objects
40
+
This means that the `readonly` modifier doesn't propagate immutability on "properties" of objects. You'll need to set it explicitly on each nested property that you want.
81
41
42
+
Check the example below:
82
43
```ts
83
44
exporttypeState= {
84
45
readonly counterContainer: {
85
-
readonlyreadonlyCounter:number,
46
+
readonlyimmutableCounter:number,
86
47
mutableCounter:number,
87
48
}
88
49
};
89
50
90
51
state.counterContainer= { mutableCounter: 1 }; // Error, cannot be mutated
91
-
state.counterContainer.readonlyCounter=1; // Error, cannot be mutated
52
+
state.counterContainer.immutableCounter=1; // Error, cannot be mutated
92
53
93
54
state.counterContainer.mutableCounter=1; // No error, can be mutated
94
55
```
95
56
96
-
> There are few utilities to help you achieve nested immutability. e.g. you can do it quite easily by using convenient `Readonly` or `ReadonlyArray` mapped types.
state.counterPairs[0].immutableCounter1=1; // Error, cannot be mutated
70
+
state.counterPairs[0].immutableCounter2=1; // Error, cannot be mutated
109
71
```
110
72
111
-
> _There are some experiments in the community to make a `ReadonlyRecursive` mapped type, but I'll need to investigate if they really works_
73
+
> _There are some experiments in the community to make a `ReadonlyRecursive` mapped type. I'll update this section of the guide as soon as they are stable_
112
74
113
75
[⇧ back to top](#table-of-contents)
114
76
115
-
### Examples
116
-
117
-
#### Reducer with classic `const types`
77
+
### Finished reducer example using `getType` helper on action creators
This pattern is focused on a KISS principle - to stay clear of abstractions and to follow a more complex but familiar JavaScript "const" based approach:
159
+
160
+
Advantages:
161
+
- familiar to standard JS "const" based approach
162
+
163
+
Disadvantages:
164
+
- significant amount of boilerplate and duplication
165
+
- more complex compared to `createAction` helper library
166
+
- necessary to export both action types and action creators to re-use in other places, e.g. `redux-saga` or `redux-observable`
0 commit comments