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
@@ -19,6 +19,30 @@ You might wonder why **undefined** is not part of the core value types. Well, th
19
19
1. It is not a serializable value. That means if you explicitly set a value to _undefined_ it will not show up in the devtools
20
20
2. Undefined values can not be tracked. That means if you were to iterate an object and look at the keys of that object, any undefined values will not be tracked. This can cause unexpected behaviour
21
21
22
+
{% hint style="info" %}
23
+
When writing Typescript you should **not** use optional values for your state \(**?**\), or use **undefined** in a union type. In a serializable state store world **null** is the value indicating _“there is no value”_.
24
+
25
+
```typescript
26
+
typeState= {
27
+
// Do not do this
28
+
foo?:string
29
+
30
+
// Do not do this
31
+
foo:string|undefined
32
+
33
+
// Do this
34
+
foo:string|null
35
+
36
+
// Or this, if there always will be a value there
37
+
foo:string
38
+
}
39
+
40
+
exportconst state:State= {
41
+
foo: null
42
+
}
43
+
```
44
+
{% endhint %}
45
+
22
46
### Naming
23
47
24
48
Each value needs to sit behind a name. Naming can be difficult, but we have some help. Even though we eventually do want to consume our application through a user interface we ideally want to avoid naming things specifically related to the environment where we show the user interface. Things like **page**, **tabs**, **modal** etc. are specific to a browser experience, maybe related to a certain size. We want to avoid those names as they should not dictate which elements are to be used with the state, that is up to the user interface to decide later. So here are some generic terms to use instead:
@@ -31,7 +55,7 @@ Each value needs to sit behind a name. Naming can be difficult, but we have some
31
55
32
56
The root value of your state tree is an object, because objects are great for holding other values. An object has keys that point to values. Most of these keys point to values that are the actual state of the application, but these keys can also represent domains of the application. A typical state structure could be:
33
57
34
-
```javascript
58
+
```typescript
35
59
{
36
60
modes: ['issues', 'admin'],
37
61
currentModeIndex: 0,
@@ -60,7 +84,7 @@ Arrays are similar to objects in the sense that they hold other values, but inst
60
84
61
85
Strings are of course used to represent text values. Names, descriptions and whatnot. But strings are also used for ids, types, etc. Strings can be used as values to reference other values. This is an important part in structuring state. For example in our **objects** example above we chose to use an array to represent the modes, using an index to point to the current mode, but we could also do:
62
86
63
-
```javascript
87
+
```typescript
64
88
{
65
89
modes: {
66
90
issues: 0,
@@ -91,38 +115,53 @@ All values, with the exception of booleans, can also be **null**. Non-existing.
91
115
92
116
A concept in Javascript called a [GETTER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) allows you to intercept accessing a property in an object. A getter is just like a plain value, it can be added or removed at any point. Getters do **not** cache the result for that very reason, but whatever state they access is tracked.
93
117
94
-
{% tabs %}
95
-
{% tab title="overmind/state.js" %}
96
-
```javascript
97
-
exportconststate= {
118
+
{% code title="overmind/state.ts" %}
119
+
```typescript
120
+
exporttypeUser= {
121
+
id:number
122
+
firstName:string
123
+
lastName:string
124
+
readonly fullName:string
125
+
}
126
+
127
+
exporttypeState= {
128
+
user:User
129
+
}
130
+
131
+
exportconst state:State= {
98
132
user: {
99
133
id: 1,
100
134
firstName: 'Bob',
101
135
lastName: 'Jackson',
102
-
jwt:'1234567'
103
-
},
104
-
getisLoggedIn() {
105
-
returnBoolean(this.user&&this.user.jwt)
136
+
get fullName(this:User) {
137
+
returnthis.firstName+''+this.lastName
138
+
}
106
139
}
107
140
}
108
141
```
109
-
{% endtab %}
110
-
{% endtabs %}
142
+
{% endcode %}
111
143
112
144
### Cached getter
113
145
114
146
When you need to do more heavy calculation or combine state from different parts of the tree you can use a plain function instead. Overmind treats these functions like a **getter**, but the returned value is cached and they can also access the root state of the application. A simple example of this would be:
115
147
116
-
{% tabs %}
117
-
{% tab title="overmind/state.js" %}
118
148
```typescript
149
+
import { Derive } from'overmind'
150
+
151
+
exporttypeState= {
152
+
title:string
153
+
upperTitle:Derive<State, string>
154
+
}
155
+
119
156
exportconst state:State= {
120
157
title: 'My awesome title',
121
158
upperTitle: state=>state.title.toUpperCase()
122
159
}
123
160
```
124
-
{% endtab %}
125
-
{% endtabs %}
161
+
162
+
{% hint style="info" %}
163
+
Is is important that you define your state with a **type**, do **NOT** use an **interface**
164
+
{% endhint %}
126
165
127
166
The first argument of the function is the state the derived function is attached to. A second argument is also passed and that is the root state of the application, allowing you to access whatever you would need. Two important traits of the derived function is:
128
167
@@ -137,20 +176,31 @@ Even though derived state is defined as functions you consume them as plain valu
137
176
138
177
### Dynamic getter
139
178
140
-
Sometimes you want to derive state based on some value coming from the user interface. You can do this by creating a function that returns a function. This can be useful for helper functions:
179
+
Sometimes you want to derive state based on some value coming from the user interface. You can do this by creating a function that returns a function. For example you want to be able to select records in a table and calculate some data based on that:
For scalability you can define **namespaces** for multiple configurations. Read more about that in [Structuring the app](../guides-1/structuring-the-app.md)
244
-
{% endhint %}
245
-
246
333
## Summary
247
334
248
335
This short guide gave you some insight into how we think about state and what state really is in an application. There is more to learn about these values and how to use them to describe the application. Please move on to other guides to learn more.
Copy file name to clipboardExpand all lines: core/typescript.md
-22Lines changed: 0 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -108,28 +108,6 @@ export const state: State = {
108
108
It is important that you use a **type** and not an **interface.** This has to do with the way Overmind resolves the state typing. ****
109
109
{% endhint %}
110
110
111
-
When writing Typescript you should **not** use optional values for your state \(**?**\), or use **undefined** in a union type. In a serializable state store world **null** is the value indicating _“there is no value”._
0 commit comments