Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typescript: add base model typing #487

Merged
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
99ae8a2
ts: enable strict null checks
hamiltoes May 14, 2020
ab1d7e1
new: Model instance and static interfaces
hamiltoes May 14, 2020
a42dd56
clean up: add jsdoc comments to model interface
hamiltoes May 14, 2020
0021860
export types, augment VueConstructor
hamiltoes May 14, 2020
54f896a
fix: remove extra closing brace
hamiltoes May 14, 2020
8a1f6e8
make model data type extend {}
hamiltoes May 15, 2020
0986160
fix: model.update() signature
hamiltoes May 15, 2020
ce6250d
ensure BaseModel implements ModelStatic and ModelInstance
hamiltoes May 15, 2020
d37514d
fix: implement ModelInstanceClone instead to ensure reset() and commi…
hamiltoes May 15, 2020
1091ea4
rename: SetupContext => ModelSetupContext to avoid name clash with @v…
hamiltoes May 15, 2020
cb17155
export Model interfaces
hamiltoes May 15, 2020
c9f2969
fix: commit() actually returns original model
hamiltoes May 15, 2020
9865f36
add explicit typing in make-base-model to ensure Model interface is i…
hamiltoes May 15, 2020
a6b0706
declare FVStore and FVGlobalModels interfaces in types, import and ex…
hamiltoes May 15, 2020
b36ea1f
allow untyped BaseModel to still access any model props
hamiltoes May 15, 2020
b4e33ff
Revert "ts: enable strict null checks"
hamiltoes May 15, 2020
73f2a9f
allow users to augment type options to disable readonly model data
hamiltoes May 15, 2020
f204e19
disable readonly model data in test
hamiltoes May 15, 2020
24de582
add merge to ModelStatic interface
hamiltoes May 15, 2020
71d0767
update tests
hamiltoes May 15, 2020
4149d78
fix: disable `model-readonly` in the test that needs it
hamiltoes May 15, 2020
3f37964
add Model typing to useFind
hamiltoes May 16, 2020
13703f5
add Model typing to useGet
hamiltoes May 16, 2020
b848318
revert useGet change that broke lazy behavior, combine watch so the A…
hamiltoes May 16, 2020
9a45916
fix test: useGet test was not actually testing null id prevents API hit
hamiltoes May 16, 2020
d3579ed
fix: augment GlobalModels onto VueConstructor and Vue instance
hamiltoes May 16, 2020
6c73938
new: if user does not augment Store or GlobalModels, use `any`
hamiltoes May 16, 2020
009824f
revert tests that casted models to any
hamiltoes May 16, 2020
bc1e7a1
docs: begin documenting base model typing
hamiltoes May 16, 2020
59477cd
fix: ModelInstanceClone: hide `clone()` and only show `__isClone: true`
hamiltoes May 16, 2020
15f9f82
fix: add `tempIdField` to `ServiceState` interface
hamiltoes May 17, 2020
4aff535
new: export AuthState interface so users can augment FeathersVuexStor…
hamiltoes May 17, 2020
89eea14
typing: improve `ServiceState` typing
hamiltoes May 17, 2020
143a61c
new: add `ModelStatic.prototype` prop
hamiltoes May 17, 2020
e56d301
fix: `find` getter always returns Paginated
hamiltoes May 17, 2020
8d49748
new: export ModelInstance and ModelInstanceClone interfaces
hamiltoes May 17, 2020
0ab21cb
simplify: combine Model and ModelClone interfaces
hamiltoes May 18, 2020
77f9c18
test: disable readonly model in another test
hamiltoes May 18, 2020
742f246
cleanup: don't use local type in make-base-model
hamiltoes May 20, 2020
9ca6680
Merge remote-tracking branch 'upstream/master' into ts/typed-base-models
hamiltoes Jun 3, 2020
353f68c
Merge remote-tracking branch 'upstream/master' into ts/typed-base-models
hamiltoes Jun 6, 2020
454abe4
pare down base model typing to non-generic
hamiltoes Jun 6, 2020
e1a0527
revert tests
hamiltoes Jun 6, 2020
31cf7a7
clean up
hamiltoes Jun 6, 2020
227d4e8
docs: update for simplified non-generic interfaces
hamiltoes Jun 6, 2020
6054e1a
clean up imports
hamiltoes Jun 6, 2020
fd7a0cd
docs: don't reference version number
hamiltoes Jun 12, 2020
0cddd7a
docs: no need to export interfaces/classes
hamiltoes Jun 12, 2020
2a4ba66
Merge commit 'refs/tags/v3.11.0^{}' into ts/typed-base-models
hamiltoes Jun 12, 2020
651107f
Merge branch 'master' into ts/typed-base-models
marshallswain Jun 22, 2020
8d86052
Merge commit 'refs/tags/v3.11.5^{}' into ts/typed-base-models
hamiltoes Jun 24, 2020
81077b3
fix: make static props mutable
hamiltoes Jun 24, 2020
2016717
cleanup: tests no longer need @ts-ignore for mutable static props
hamiltoes Jun 24, 2020
beff982
Merge remote-tracking branch 'upstream/master' into ts/typed-base-models
hamiltoes Sep 1, 2020
bd96d6d
fix: use more verbose, quirk-free computed
hamiltoes Sep 1, 2020
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
15 changes: 15 additions & 0 deletions docs/composition-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,21 @@ export default new Router({

Now, the `Post.vue` file only requires to have a `prop` named `id`. Vue Router will pass the params from the route as props to the component. See the [first useGet example](#useget) for a component that would work with the above route. The vue-router documentation has more information about [Passing Props to Route Components](https://router.vuejs.org/guide/essentials/passing-props.html#passing-props-to-route-components)

### Composing with Model types

Both `useGet` and `useFind` have an optional type parameter for the Model type which is used as the type for the returned item(s).

```ts
// Destructure Model class from global models object
const { User } = Vue.$FeathersVuex.api

// use useGet with User Model
useGet<typeof User.prototype>(/* ... */)

// use useFind with User Model
useFind<typeof User.prototype>(/* ... */)
```

## Conventions for Development

### Params are Computed
Expand Down
71 changes: 71 additions & 0 deletions docs/model-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,77 @@ User.instanceDefaults = function() {
}
```

### BaseModel typing

BaseModel typing gives helpful IDE autocomplete and errors when using Model classes.

Since Feathers-Vuex doesn't know what your data looks like, you will need to help define your underlying model data's interface.

By default, Model classes are `string` indexable with value of type `any`. This isn't super helpful...

```ts
// Just like before, we define our class as an extension of BaseModel
class User extends BaseModel { /* ... */ }

// Augment the User Model interface
interface User {
email: string
password: string
}
```

Now, whenever we access a `User` model, all fields defined in the interface will be available in IDE auto-complete/intellisense along with the model methods/props.

If you already have a User interface defined under a different name, just define a new interface with the same name as your Model class like so

```ts
// if our User interface already exists as UserRecord
interface User extends UserRecord {}
```

To further enhance typing, you can augment FeathersVuex types to aid development in other parts of your app. It's important to note the differences in the following example if you do or do not setup a `serverAlias`.

```ts
// src/store/user.store.ts
import { ServiceState } from 'feathers-vuex'

class User extends BaseModel { /* ... */ }
interface User { /* ... */ }
const servicePath = 'users'

declare module "feathers-vuex" {
interface FeathersVuexStoreState {
[servicePath]: ServiceState<User>
}

// Only if you setup FeathersVuex without a serverAlias!!
interface FeathersVuexGlobalModels {
User: typeof User
}
}

// Only if you setup FeathersVuex with a serverAlias!!
declare module "src/store" {
interface MyApiModels {
User: typeof User
}
}
```

If you have setup a `serverAlias`, you need to add the following to `src/store/index.ts`.

```ts
// src/store/index.ts
export interface MyApiModels { /* Let each service augment this interface */ }
declare module "feathers-vuex" {
interface FeathersVuexGlobalModels {
'my-api-name': MyApiModels
}
}
```

Replace `my-api-name` with the `serverAlias` you used when setting up FeathersVuex.

## Model attributes

The following attributes are available on each model:
Expand Down
5 changes: 4 additions & 1 deletion src/auth-module/auth-module.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ eslint
@typescript-eslint/explicit-function-return-type: 0,
@typescript-eslint/no-explicit-any: 0
*/
import { AuthState } from './types'

export default function setupAuthState({
userService,
serverAlias,
responseEntityField = 'user',
entityIdField = 'userId'
}) {
const state = {
const state: AuthState = {
accessToken: null, // The JWT
payload: null, // The JWT payload
entityIdField,
Expand All @@ -21,6 +23,7 @@ export default function setupAuthState({
errorOnAuthenticate: null,
errorOnLogout: null,
user: null, // For a reactive user object, use the `user` getter.
userService: null,
serverAlias
}
// If a userService string was passed, add a user attribute
Expand Down
3 changes: 3 additions & 0 deletions src/auth-module/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ export interface AuthState {
accessToken: string
payload: {}
entityIdField: string
responseEntityField: string

isAuthenticatePending: boolean
isLogoutPending: boolean

errorOnAuthenticate: Error
errorOnLogout: Error
user: {}
userService: string
serverAlias: string
}
26 changes: 23 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,21 @@ import prepareMakeAuthPlugin from './auth-module/make-auth-plugin'
import useFind from './useFind'
import useGet from './useGet'

import { FeathersVuexOptions, HandleEvents } from './service-module/types'
import {
FeathersVuexOptions,
HandleEvents,
Model,
ModelStatic,
ModelSetupContext,
Id,
FeathersVuexStoreState,
FeathersVuexGlobalModels,
GlobalModels,
} from './service-module/types'
import { initAuth, hydrateApi } from './utils'
import { FeathersVuex } from './vue-plugin/vue-plugin'
import { ServiceState } from './service-module/service-module.state'
import { AuthState } from './auth-module/types'
const events = ['created', 'patched', 'updated', 'removed']

const defaults: FeathersVuexOptions = {
Expand Down Expand Up @@ -73,7 +85,7 @@ export default function feathersVuex(feathers, options: FeathersVuexOptions) {
BaseModel,
makeAuthPlugin,
FeathersVuex,
models,
models: models as GlobalModels,
clients
}
}
Expand All @@ -92,5 +104,13 @@ export {
models,
clients,
useFind,
useGet
useGet,
AuthState,
Id,
Model,
ModelStatic,
ModelSetupContext,
ServiceState,
FeathersVuexGlobalModels,
FeathersVuexStoreState,
}
Loading