🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

nuxt-typed-vuex

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nuxt-typed-vuex - npm Package Compare versions

Comparing version

to
0.1.6

7

CHANGELOG.md

@@ -5,2 +5,9 @@ # Changelog

### [0.1.6](https://github.com/danielroe/nuxt-typed-vuex/compare/v0.1.5...v0.1.6) (2019-10-11)
### Features
* add rootState and rootGetters type helpers ([2661017](https://github.com/danielroe/nuxt-typed-vuex/commit/2661017))
### [0.1.5](https://github.com/danielroe/nuxt-typed-vuex/compare/v0.1.4...v0.1.5) (2019-10-06)

@@ -7,0 +14,0 @@

18

lib/utils.d.ts

@@ -17,4 +17,4 @@ import { Store, GetterTree, MutationTree, ActionTree, DispatchOptions, CommitOptions } from 'vuex';

};
declare type ModuleTransformer<T> = T extends NuxtModules ? {
[P in keyof T]: MergedStoreType<T[P] & BlankStore>;
declare type ModuleTransformer<T, O = string> = T extends NuxtModules ? {
[P in keyof T]: MergedStoreType<T[P] & BlankStore, O>;
} : {};

@@ -46,3 +46,3 @@ interface BlankStore {

}
declare type MergedStoreType<T extends NuxtStore> = StateType<T['state']> & GettersTransformer<T['getters']> & MutationsTransformer<T['mutations']> & ActionTransformer<T['actions']> & ModuleTransformer<T['modules']>;
declare type MergedStoreType<T extends NuxtStore, K = string> = ('state' extends K ? StateType<T['state']> : {}) & ('getters' extends K ? GettersTransformer<T['getters']> : {}) & ('mutations' extends K ? MutationsTransformer<T['mutations']> : {}) & ('actions' extends K ? ActionTransformer<T['actions']> : {}) & ('modules' extends K ? ModuleTransformer<T['modules']> : {});
declare type StoreParameter<T extends () => any> = Parameters<T>[1] extends undefined ? never : Parameters<T>[1];

@@ -67,2 +67,4 @@ interface Dispatch<T extends Record<string, () => any>> {

};
export declare type RootStateHelper<T extends Required<NuxtStore>> = StateType<T['state']> & ModuleTransformer<T['modules'], 'state'>;
export declare type RootGettersHelper<T extends Required<NuxtStore>> = GettersTransformer<T['getters']> & ModuleTransformer<T['modules'], 'getters'>;
export declare const getStoreType: <T extends Record<string, any>, G, M, A, S extends Record<string, Partial<NuxtStore> & {

@@ -72,2 +74,4 @@ state: () => unknown;

actionContext: ActionContext<NuxtStoreInput<T, G, M, A, S> & BlankStore>;
rootState: RootStateHelper<NuxtStoreInput<T, G, M, A, S> & BlankStore>;
rootGetters: RootGettersHelper<NuxtStoreInput<T, G, M, A, S> & BlankStore>;
storeInstance: ActionContext<NuxtStoreInput<T, G, M, A, S> & BlankStore> & Pick<Store<StateType<T>>, "app" | "replaceState" | "subscribe" | "subscribeAction" | "watch" | "registerModule" | "unregisterModule" | "hotUpdate" | "$router">;

@@ -77,6 +81,6 @@ };

state: () => unknown;
}>>(store: NuxtStoreInput<T, G, M, A, S>) => MergedStoreType<NuxtStoreInput<T, G, M, A, S> & BlankStore>;
export declare const useAccessor: <T extends Record<string, any>, G extends GetterTree<StateType<T>, StateType<T>>, M extends MutationTree<StateType<T>>, A extends ActionTree<StateType<T>, StateType<T>>, S extends Record<string, Partial<NuxtStore> & {
}>>(store: NuxtStoreInput<T, G, M, A, S>) => MergedStoreType<NuxtStoreInput<T, G, M, A, S> & BlankStore, string>;
export declare const useAccessor: <T extends Record<string, any>, G extends GetterTree<StateType<T>, any>, M extends MutationTree<StateType<T>>, A extends ActionTree<StateType<T>, any>, S extends Record<string, Partial<NuxtStore> & {
state: () => unknown;
}>>(store: Store<StateType<T>>, input: Required<NuxtStoreInput<T, G, M, A, S>>) => MergedStoreType<NuxtStoreInput<T, G, M, A, S> & BlankStore>;
}>>(store: Store<StateType<T>>, input: Required<NuxtStoreInput<T, G, M, A, S>>) => MergedStoreType<NuxtStoreInput<T, G, M, A, S> & BlankStore, string>;
export declare const getAccessorFromStore: (pattern: any) => (store: Store<any>) => any;

@@ -91,3 +95,3 @@ export declare const getterTree: <S, T extends GetterTree<StateType<S>, any>>(_state: S, tree: T) => T;

}
export declare const actionTree: <S extends Record<string, any>, G extends GetterTree<StateType<S>, {}>, M extends MutationTree<StateType<S>>, T extends ModifiedActionTree<Required<NuxtStoreInput<S, G, M, {}, {}>>>>(_store: NuxtStoreInput<S, G, M, {}, {}>, tree: T) => T;
export declare const actionTree: <S extends Record<string, any>, G extends GetterTree<StateType<S>, any>, M extends MutationTree<StateType<S>>, T extends ModifiedActionTree<Required<NuxtStoreInput<S, G, M, {}, {}>>>>(_store: NuxtStoreInput<S, G, M, {}, {}>, tree: T) => T;
export {};
export const getStoreType = (store) => {
return {
actionContext: {},
rootState: {},
rootGetters: {},
storeInstance: {},

@@ -5,0 +7,0 @@ };

{
"name": "nuxt-typed-vuex",
"version": "0.1.5",
"version": "0.1.6",
"description": "A typed store accessor for Nuxt.",

@@ -20,3 +20,3 @@ "repository": "danielroe/nuxt-typed-vuex",

"build": "tsc",
"prepublish": "yarn build",
"prepare": "yarn build",
"release": "yarn test && standard-version && git push --follow-tags && npm publish",

@@ -27,12 +27,12 @@ "generate": "yarn build && yarn nuxt generate test/fixture",

"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/core": "^7.6.4",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "^7.6.2",
"@babel/preset-env": "^7.6.3",
"@babel/preset-typescript": "^7.6.0",
"@nuxt/typescript-build": "^0.3.1",
"@nuxt/typescript-runtime": "^0.2.1",
"@nuxtjs/eslint-config": "^1.1.2",
"@babel/preset-typescript": "^7.6.0",
"@nuxt/typescript-build": "^0.3.0",
"@nuxt/typescript-runtime": "^0.2.0",
"@types/jest": "^24.0.18",
"@typescript-eslint/eslint-plugin": "^2.3.1",
"@typescript-eslint/parser": "^2.3.1",
"@typescript-eslint/eslint-plugin": "^2.3.3",
"@typescript-eslint/parser": "^2.3.3",
"babel-eslint": "^10.0.3",

@@ -52,4 +52,9 @@ "babel-jest": "^24.9.0",

"standard-version": "^7.0.0",
"typescript": "^3.6.3"
"ts-loader": "^6.2.0",
"typescript": "^3.6.4"
},
"dependencies": {
"@nuxt/types": "*",
"vuex": "*"
}
}

@@ -1,3 +0,20 @@

# 🏦 Nuxt Typed Vuex
<h1 align="center" >🏦 Nuxt Typed Vuex</h1>
<p align="center">A vanilla, strongly-typed store for Nuxt</p>
<p align="center">
<a href="https://david-dm.org/danielroe/nuxt-typed-vuex">
<img alt="" src="https://david-dm.org/danielroe/nuxt-typed-vuex/status.svg?style=flat-square">
</a>
<a href="https://npmjs.com/package/nuxt-typed-vuex">
<img alt="" src="https://img.shields.io/npm/v/nuxt-typed-vuex/latest.svg?style=flat-square">
</a>
<a href="https://npmjs.com/package/nuxt-typed-vuex">
<img alt="" src="https://img.shields.io/npm/dt/nuxt-typed-vuex.svg?style=flat-square">
</a>
</p>
<p align="center">
<a href="https://nuxt-typed-vuex.danielcroe.com">Read documentation</a>
</p>
## Summary

@@ -7,4 +24,2 @@

**Note**: This has been developed to suit my needs but additional use cases and contributions are very welcome.
![Image showing autocomplete on this.$accessor](./docs/images/screenshot1.png)

@@ -14,298 +29,4 @@

## Usage
**Note**: This has been developed to suit my needs but additional use cases and contributions are very welcome.
Add module to your `nuxt.config`:
```ts
modules: [
'nuxt-typed-vuex',
],
```
You will now have access to an injected store accessor (`this.$accessor`) throughout your project. Getters, state (if a getter with the same name doesn't already exist), actions and mutations are available at the root level, with submodules nested under their own namespace.
### Typing the accessor
The accessor injected by this module is not typed by default, so you will need to add your own type definitions, for which a helper function, `getAccessorType`, is provided. This function only serves to return the correct type of the accessor so that it can be used where you see fit.
```ts
import { getAccessorType } from 'nuxt-typed-vuex'
import * as store from '~/store'
...
const accessorType = getAccessorType(store)
// Now you can access the type of the accessor.
const accessor: typeof accessorType
```
### Typing actions within the store
I recommend the following patterns:
**Note**: There are a number of helper functions created to assist in typing actions within the store, although they are strictly optional. They do not **transform** the objects provided to them, but simply inject the correct types.
#### State
If there is any ambiguity in your initial object (of particular note are empty arrays), make sure to provide types as well.
```ts
export const state = () => ({
emails: [] as string[],
})
// If needed, you can define state for use in vanilla Vuex types
export type RootState = ReturnType<typeof state>
```
#### Getters
Vanilla getters are functions that receive state, as well as the other getters. `nuxt-typed-vuex` can't type the getters received, but does provide a helper function to reduce boilerplate:
```ts
// Vanilla
export const getters = {
email: (state: RootState) => (state.emails.length ? state.emails[0] : ''),
aDependentGetter: (_state: RootState, getters: any) => getters.email,
}
// Helper function
import { getterTree } from 'nuxt-typed-vuex'
export const getters = getterTree(state, {
email: state => (state.emails.length ? state.emails[0] : ''),
aDependentGetter: (_state, getters) => getters.email,
})
```
#### Mutations
Vanilla mutations are functions that receive state and an optional payload. Again, a helper function is provided to reduce boilerplate.
```ts
// Vanilla
export const mutations = {
setEmail(state: RootState, newValue: string) {
state.email = newValue
},
initialiseStore() {
console.log('initialised')
},
}
// Helper function
import { mutationTree } from 'nuxt-typed-vuex'
export const getters = mutationTree(state, {
setEmail(state, newValue: string) {
state.email = newValue
},
initialiseStore() {
console.log('initialised')
},
})
```
#### Actions
Actions are more complicated. In vanilla Vuex, they can either be objects (not supported by `nuxt-typed-vuex`) or async functions that have access to an instance (through which they can access the strongly-typed accessor injected above).
```ts
// Vanilla
export const actions = {
async resetEmail(
this: Store<RootState>,
{ commit }: ActionContext<RootState, RootState>,
payload: string
) {
// Not typed - avoid
commit('initialiseStore')
// Typed
this.app.$accessor.initialiseStore()
},
}
// Helper function
export const actions = actionTree(
{ state, getters, mutations },
{
async resetEmail({ commit, dispatch }) {
// Typed
commit('initialiseStore')
// Not typed
dispatch('resetEmail')
// Typed
this.app.$accessor.resetEmail()
},
}
)
```
#### Accessing namespaced state, getters, actions and mutations from mutations
This is currently a work in progress.
#### `getStoreType` (deprecated)
There is another helper function: `getStoreType`.
This is largely obviated by the `actionTree` helper above.
It does not correctly type actions and mutations for submodules, but may be useful for simpler setups. Consider it a placeholder for future development.
```ts
import { getStoreType } from 'nuxt-typed-vuex'
import * as store from '~/store'
const { storeType, storeInstance } = getStoreType(store)
const store: storeInstance
// You will now get type checking on getters, actions, state and mutations
store.commit('SAMPLE_MUTATION', 30)
```
## Example
### Setup
`store/index.ts`:
```ts
import { getAccessorType } from 'nuxt-typed-vuex'
import * as submodule from '~/store/submodule'
export const state = () => ({
email: '',
ids: [] as number[],
})
type RootState = ReturnType<typeof state>
export const getters = {
email: (state: RootState) => state.email,
}
export const mutations = {
SET_EMAIL(state: RootState, newValue: string) {
state.email = newValue
},
}
export const actions = {
async resetEmail({ commit }: ActionContext<RootState, RootState>) {
commit('SET_EMAIL', '')
},
}
export const accessorType = getAccessorType({
actions,
getters,
mutations,
state,
modules: {
// The key (submodule) needs to match the Nuxt namespace (e.g. submodule.ts)
submodule,
},
})
```
`index.d.ts`:
```ts
import { accessorType } from '~/store'
declare module 'vue/types/vue' {
interface Vue {
$accessor: typeof accessorType
}
}
declare module '@nuxt/types' {
interface NuxtAppOptions {
$accessor: typeof accessorType
}
}
```
### Usage
#### Within components
`components/sampleComponent.vue`:
```ts
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
fetch({ app: { $accessor } }) {
// Accessing within fetch or asyncData
$accessor.fetchItems()
},
})
export default class SampleComponent extends Vue {
get email() {
// This (behind the scenes) returns this.$store.getters['email']
return this.$accessor.email
}
resetEmail() {
// Executes this.$store.dispatch('submodule/resetEmail', 'thing')
this.$accessor.submodule.submoduleAction('thing')
}
}
```
#### Middleware
`middleware/test.ts`:
```ts
import { Context } from '@nuxt/types'
export default ({ redirect, app: { $accessor } }: Context) => {
// You can access the store here
if ($accessor.email) return redirect('/')
}
```
## Notes
### Usage with IE11
You may need to transpile this module for usage with IE11.
`nuxt.config`:
```ts
...
build: {
transpile: [
/nuxt-typed-vuex/
],
},
```
## Key limitations and assumptions
1. You should not use the Vuex helper functions, such as `GetterTree`, in your store, as it interferes with type inference.
However, your store properties will be checked at the point you pass them into `getAccessorType` and you will get an error if (for example) you pass in a getter that doesn't match Vuex's type signature for a getter.
2. This may require additional work for submodules split into separate `state.ts`, `actions.ts`, `mutations.ts` and `getters.ts`.
3. Note that this does not support [object-style commits](https://vuex.vuejs.org/guide/mutations.html#object-style-commit).
## License
[MIT License](./LICENSE) - Copyright &copy; Daniel Roe

Sorry, the diff of this file is not supported yet