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: docs/markdown/2_redux.md
+47-110
Original file line number
Diff line number
Diff line change
@@ -2,14 +2,15 @@
2
2
3
3
## Action Creators
4
4
5
-
> Using Typesafe Action Creators helpers for Redux [`typesafe-actions`](https://github.com/piotrwitek/typesafe-actions#typesafe-actions)
5
+
> We'll be using a battle-tested library [](https://www.npmjs.com/package/typesafe-actions)
6
+
that automates and simplify maintenace of **type annotations in Redux Architectures**[`typesafe-actions`](https://github.com/piotrwitek/typesafe-actions#typesafe-actions)
6
7
7
-
A recommended approach is to use a simple functional helper 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 specialized functional helpers available that will help you to further reduce tedious boilerplate and type-annotations in common scenarios like reducers (using [`getType`](https://github.com/piotrwitek/typesafe-actions#gettype)) or epics (using [`isActionOf`](https://github.com/piotrwitek/typesafe-actions#isactionof)).
9
-
All that without losing type-safety! Please check this very short [Tutorial](https://github.com/piotrwitek/typesafe-actions#tutorial)
8
+
### You should read [The Mighty Tutorial](https://github.com/piotrwitek/typesafe-actions#behold-the-mighty-tutorial) to learn it all the easy way!
A solution below is using simple factory function to automate the creation of type-safe action creators. The goal is to reduce the maintainability and code repetition of type annotations for actions and creators and the result is completely typesafe action-creators and their actions.
@@ -18,10 +19,11 @@ All that without losing type-safety! Please check this very short [Tutorial](htt
18
19
## Reducers
19
20
20
21
### State with Type-level Immutability
21
-
Declare reducer `State` type with `readonly` modifier to get "type level" immutability
22
+
Declare reducer `State` type with `readonly` modifier to get compile time immutability
22
23
```ts
23
24
exporttypeState= {
24
-
readonly counter:number,
25
+
readonly counter:number;
26
+
readonly todos:ReadonlyArray<string>;
25
27
};
26
28
```
27
29
@@ -31,25 +33,34 @@ export const initialState: State = {
31
33
counter: 0,
32
34
}; // OK
33
35
34
-
initialState.counter=3; // Error, cannot be mutated
36
+
initialState.counter=3; // TS Error: cannot be mutated
37
+
```
38
+
39
+
It's great for **Arrays in JS** because it will error when using mutator methods like (`push`, `pop`, `splice`, ...), but it'll still allow immutable methods like (`concat`, `map`, `slice`,...).
40
+
```ts
41
+
state.todos.push('Learn about tagged union types') // TS Error: Property 'push' does not exist on type 'ReadonlyArray<string>'
42
+
const newTodos =state.todos.concat('Learn about tagged union types') // OK
35
43
```
36
44
37
-
#### Caveat: Readonly does not provide a recursive immutability on objects
38
-
This means that the `readonly` modifier doesn't propagate immutability down to "properties" of objects. You'll need to set it explicitly on each nested property that you want.
45
+
#### Caveat: Readonly is not recursive
46
+
This means that the `readonly` modifier doesn't propagate immutability down the nested structure of objects. You'll need to mark each property on each level explicitly.
47
+
48
+
To fix this we can use [`DeepReadonly`](https://github.com/piotrwitek/utility-types#deepreadonlyt) type (available in `utility-types` npm library - collection of reusable types extending the collection of **standard-lib** in TypeScript.
39
49
40
50
Check the example below:
41
51
```ts
42
-
exporttypeState= {
43
-
readonly containerObject: {
44
-
readonly immutableProp:number,
45
-
mutableProp:number,
46
-
}
47
-
};
52
+
import { DeepReadonly } from'utility-types';
48
53
49
-
state.containerObject= { mutableProp: 1 }; // Error, cannot be mutated
50
-
state.containerObject.immutableProp=1; // Error, cannot be mutated
54
+
exporttypeState=DeepReadonly<{
55
+
containerObject: {
56
+
innerValue:number,
57
+
numbers:number[],
58
+
}
59
+
}>;
51
60
52
-
state.containerObject.mutableProp=1; // OK! No error, can be mutated
state.counterPairs[0].immutableCounter1=1; //TS Error: cannot be mutated
79
+
state.counterPairs[0].immutableCounter2=1; //TS Error: cannot be mutated
69
80
```
70
81
71
-
> _There is a new (work in progress) feature called **Conditional Types**, that will allow `ReadonlyRecursive` mapped type_
72
-
73
82
[⇧ back to top](#table-of-contents)
74
83
75
84
### Typing reducer
76
-
> using type inference with [Discriminated Union types](https://www.typescriptlang.org/docs/handbook/advanced-types.html)
85
+
> to understand following section make sure to learn about [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html), [Control flow analysis](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#control-flow-based-type-analysis) and [Tagged union types](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#tagged-union-types)
When creating the store, use rootReducer. This will set-up a **strongly typed Store instance**with type inference.
112
-
> The resulting store instance methods like `getState` or `dispatch` will be type checked and expose type errors
115
+
When creating a store instance we don't need to provide any additional types. It will set-up a **type-safe Store instance**using type inference.
116
+
> The resulting store instance methods like `getState` or `dispatch` will be type checked and will expose all type errors
113
117
114
-
::example='../../playground/src/store.ts'::
118
+
::example='../../playground/src/store/store.ts'::
115
119
116
120
---
117
121
118
122
## Async Flow
119
123
120
124
### "redux-observable"
121
125
122
-
Use `isActionOf` helper to filter actions and to narrow `RootAction` union type to a specific "action type" down the stream.
126
+
### For more examples and in-depth explanation you should read [The Mighty Tutorial](https://github.com/piotrwitek/typesafe-actions#behold-the-mighty-tutorial) to learn it all the easy way!
@@ -131,73 +135,6 @@ Use `isActionOf` helper to filter actions and to narrow `RootAction` union type
131
135
132
136
### "reselect"
133
137
134
-
```ts
135
-
import { createSelector } from'reselect';
136
-
137
-
import { RootState } from'@src/redux';
138
-
139
-
exportconst getTodos =
140
-
(state:RootState) =>state.todos.todos;
141
-
142
-
exportconst getTodosFilter =
143
-
(state:RootState) =>state.todos.todosFilter;
144
-
145
-
exportconst getFilteredTodos =createSelector(
146
-
getTodos, getTodosFilter,
147
-
(todos, todosFilter) => {
148
-
switch (todosFilter) {
149
-
case'completed':
150
-
returntodos.filter((t) =>t.completed);
151
-
case'active':
152
-
returntodos.filter((t) =>!t.completed);
153
-
154
-
default:
155
-
returntodos;
156
-
}
157
-
},
158
-
);
159
-
```
160
-
161
-
[⇧ back to top](#table-of-contents)
162
-
163
-
---
164
-
165
-
### Action Creators - Alternative Pattern
166
-
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:
167
-
168
-
Advantages:
169
-
- familiar to standard JS "const" based approach
170
-
171
-
Disadvantages:
172
-
- significant amount of boilerplate and duplication
173
-
- more complex compared to `createAction` helper library
174
-
- necessary to export both action types and action creators to re-use in other places, e.g. `redux-saga` or `redux-observable`
Copy file name to clipboardExpand all lines: docs/markdown/4_recipes.md
+3-3
Original file line number
Diff line number
Diff line change
@@ -2,8 +2,8 @@
2
2
3
3
### tsconfig.json
4
4
- Recommended baseline config carefully optimized for strict type-checking and optimal webpack workflow
5
-
- Install [`tslib`](https://www.npmjs.com/package/tslib) to cut on bundle size, by using external transpiltion helper module instead of adding them inline: `npm i tslib`
6
-
- Example setup for project relative path imports with Webpack
5
+
- 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`
6
+
- Example "paths" setup for baseUrl relative imports with Webpack
#### To quick-fix missing type declarations 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)
> More advanced scenarios for working with vendor module declarations can be found here [Official TypeScript Docs](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md#working-with-other-javascript-libraries)
Copy file name to clipboardExpand all lines: docs/markdown/_intro.md
+8-6
Original file line number
Diff line number
Diff line change
@@ -1,14 +1,16 @@
1
-
# React & Redux in TypeScript - Static Typing Guide
1
+
##React & Redux in TypeScript - Static Typing Guide
2
2
3
3
_"This guide is a **living compendium** documenting the most important patterns and recipes on how to use **React** (and it's Ecosystem) in a **functional style with TypeScript** and to make your code **completely type-safe** while focusing on a **conciseness of type annotations** so it's a minimal effort to write and to maintain types in the long run."_
4
4
5
-
To provide the best experience we focus on the symbiosis of type-safe complementary libraries and learning the concepts like [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html), [Control flow analysis](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#control-flow-based-type-analysis), [Generics](https://www.typescriptlang.org/docs/handbook/generics.html) and some [Advanced Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html).
6
-
7
5
[](https://gitter.im/react-redux-typescript-guide/Lobby)
8
6
9
-
> _Now compatible with **TypeScript v2.8.3**_
7
+
> #### _Found it usefull? Want more updates?_[**Show your support by giving a :star:**](https://github.com/piotrwitek/react-redux-typescript-patterns/stargazers)
8
+
9
+
> _[The Mighty Tutorial](https://github.com/piotrwitek/typesafe-actions#behold-the-mighty-tutorial) for completely typesafe Redux Architecture_:book:
10
+
11
+
> _Reference implementation of Todo-App with `typesafe-actions`: https://codesandbox.io/s/github/piotrwitek/typesafe-actions-todo-app_:computer:
10
12
11
-
> #### _Found it usefull? Want more updates?_[**Give it a :star2:**](https://github.com/piotrwitek/react-redux-typescript-patterns/stargazers)
13
+
> _Now compatible with **TypeScript v2.8.3** (rewritten using conditional types)_:tada:
12
14
13
15
### Goals
14
16
- Complete type safety (with [`--strict`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) flag) without loosing type information downstream through all the layers of our application (e.g. no type assertions or hacking with `any` type)
@@ -17,8 +19,8 @@ To provide the best experience we focus on the symbiosis of type-safe complement
17
19
18
20
### Complementary Projects
19
21
- Typesafe Action Creators for Redux / Flux Architectures [typesafe-actions](https://github.com/piotrwitek/typesafe-actions)
20
-
- Reference implementation of Todo-App: [typesafe-actions-todo-app](https://github.com/piotrwitek/typesafe-actions-todo-app)
21
22
- Utility Types for TypeScript: [utility-types](https://github.com/piotrwitek/utility-types)
23
+
- Reference implementation of Todo-App: [typesafe-actions-todo-app](https://github.com/piotrwitek/typesafe-actions-todo-app)
22
24
23
25
### Playground Project
24
26
[](https://app.codeship.com/projects/262359)
0 commit comments