Skip to content

Commit bc1e7a1

Browse files
committed
docs: begin documenting base model typing
1 parent 009824f commit bc1e7a1

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

docs/model-classes.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,88 @@ User.instanceDefaults = function() {
5151
}
5252
```
5353

54+
### BaseModel typing <Badge text="3.11.0+" />
55+
56+
Version `3.11.0` brings explicit typing to the BaseModel. This gives helpful IDE autocomplete and errors when Model classes or instances
57+
are used incorrectly.
58+
59+
One major change here is that the BaseModel now enforces Vuex strict mode compliance by default and encourages proper state management using
60+
the clone and commit pattern. It does this by declaring the underlying model data `readonly`. This means the TS compiler will error at any
61+
attempt to directly assign to a model.
62+
63+
Take the `User` class from above
64+
65+
```ts
66+
// wrong
67+
const user = new User()
68+
user.email = '[email protected]' // <- TS will error here
69+
```
70+
71+
The proper way to edit an existing `User` instance is to clone it, edit the *clone's* props, and then commit the changes.
72+
This ensures changes don't propagate to the rest of the app until ready.
73+
74+
```ts
75+
// correct
76+
const clone = user.clone()
77+
clone.email = '[email protected]' // <- No error here
78+
clone.commit()
79+
```
80+
81+
You can disable this `readonly` behavior if desired. In `feathers-client.ts`, augment FeathersVuex's typing
82+
83+
```ts
84+
declare module 'feathers-vuex' {
85+
interface FeathersVuexTypeOptions {
86+
'model-readonly': false
87+
}
88+
}
89+
```
90+
91+
### Casting the BaseModel <Badge text="3.11.0+" />
92+
93+
Typescript users can further enhance typing on Model classes and instances by passing their data's underlying structure as an interface
94+
to `castBaseModel<T>()`. This gives helpful type hints and autocomplete from your IDE when interacting with your underlying Model data.
95+
96+
To take advantage of this, first we need to update `feathers-client.ts` to export the new function
97+
98+
```ts
99+
// feathers-client.ts
100+
const {/* other props, */ castBaseModel } = feathersVuex(/* ... */)
101+
102+
// Export `castBaseModel` too
103+
export { /* other props */ castBaseModel }
104+
```
105+
106+
Now we can use `castBaseModel()` when defining our Model class
107+
108+
```ts
109+
import feathersClient, { makeServicePlugin, castBaseModel } from '../feathers-client'
110+
111+
// Define an interface for your underlying data
112+
interface UserData {
113+
id: number
114+
email: string
115+
password: string
116+
}
117+
118+
// Pass interface to castBaseModel()
119+
class TypedUser extends castBaseModel<UserData>() {
120+
static readonly modelName = 'TypedUser'
121+
}
122+
123+
// Make the plugin just as before
124+
const servicePath = 'users'
125+
const servicePlugin = makeServicePlugin({
126+
Model: TypedUser,
127+
service: feathersClient.service(servicePath),
128+
servicePath
129+
})
130+
```
131+
132+
Now our IDE knows that instances of `TypedUser` have all props defined by the `UserData` interface.
133+
134+
By default, the BaseModel uses `{ [key: string]: any }` as the underlying data interface meaning any prop can be accessed/assigned to.
135+
54136
## Model attributes
55137

56138
The following attributes are available on each model:

0 commit comments

Comments
 (0)