mrcrowl / vuex-typex Goto Github PK
View Code? Open in Web Editor NEWTypescript builder for strongly-typed access to Vuex Store modules
License: MIT License
Typescript builder for strongly-typed access to Vuex Store modules
License: MIT License
Hi @mrcrowl
I wanted to share with you an upgrade I managed to create to vuex-typex with the help infer types from Typescript 2.8!
I love your extension and I’m using it every day so I wanted to contribute to it!
Instead of committing or dispatching each function, I can just pass an Object regrouping all mutations
I’m prototyping it on my project and for the moment it’s working for the mutations.
Here is a piece of code of how I managed to do that
type IsValidArg<T> = T extends object ? (keyof T extends never ? false : true) : true;
type inferMutations<T> = T extends (state, payload: infer P) => void
? IsValidArg<P> extends true
? (payload: P) => void
: () => void
: () => void;
export const storeBuilder = getStoreBuilder<any>();
export function stateBuilder<S>(state: S, name: string) {
const { commit } = storeBuilder.module<S>(name, state);
const registerMutations = <T>(mutations: T): { [K in keyof T]: inferMutations<T[K]> } => {
Object.keys(mutations).map(m => {
mutations[m] = commit(mutations[m]);
});
return mutations as any;
};
return { registerMutations };
}
By the way, it’s working when passing ‘any’ type!
Still working on optional parameters
Link to the module declarations
Module folder;
Store declaration
Store init
Hope it helps those who want to test this lib I really love it!
Could someone give an example for declaration using nested module?
I get an error from the sample code:
dispatchRestoreSavedBasket: moduleBuilder.dispatch(restoreSavedBasket)
gives:
[ts]
Argument of type '(context: ActionContext<BasketState, RootState>) => Promise<void>' is not assignable to parameter of type 'ActionHandler<BasketState, RootState, {}, void>'.
Types of parameters 'context' and 'context' are incompatible.
Type 'BareActionContext<BasketState, RootState>' is not assignable to type 'ActionContext<BasketState, RootState>'.
Property 'dispatch' is missing in type 'BareActionContext<BasketState, RootState>'.
const restoreSavedBasket: (context: ActionContext<BasketState, RootState>) => Promise<void>
"vue": "^2.5.14",
"vue-class-component": "^6.2.0",
"vue-cookie": "1.1.4",
"vue-loader": "^14.2.1",
"vue-router": "^3.0.1",
"vue-server-renderer": "^2.5.14",
"vue-ssr-webpack-plugin": "^3.0.0",
"vue-style-loader": "^4.0.2",
"vue-template-compiler": "^2.5.14",
"vuex": "^3.0.1",
"vuex-class": "^0.3.0",
"vuex-router-sync": "^5.0.0",
"vuex-typex": "^3.0.1"
tried to dynamically register modules for different pages, and got this error:
"Can't add module after vuexStore() has been called"
is this achievable somehow? register all modules for all pages doesn't seem to be ideal.
thanks
It seems like the .d.ts
file is missing in the 3.1.7 release.
Hi all
I have a Store module like this:
import { IRobotState } from '@types'
import {storeBuilder} from "./StoreBuilder"
import axios from 'axios'
//State
const state: IRobotState = {
serieID : "",
productionCount: 0,
rapidValue: 0
}
const RobotStateMod = storeBuilder.module<IRobotState>("RobotModule", state);
const stateGetter = RobotStateMod.state();
namespace Getters {
export const getters = {
get getRobotSerieID() { return state.serieID },
get getProductionCount() { return state.productionCount; }
}
}
namespace Mutations {
function setRobotSerieID(state:IRobotState, robotSerieId: String)
{
state.serieID = robotSerieId;
}
export const mutations = {
commitSetRobotSerieID: RobotStateMod.commit(setRobotSerieID)
}
}
namespace Actions {
async function getRobotSerieID()
{
}
export const actions = {
dispatchGetRobotSerieID: RobotStateMod.dispatch(getRobotSerieID)
}
}
// Module
const RobotStateModule = {
get state() { return stateGetter()},
getters: Getters.getters,
mutations: Mutations.mutations,
actions: Actions.actions
}
export default RobotStateModule;
but it gives the following error when I try to load the page after production build - in dev build it works fine:
Uncaught Error: Vuex handler functions must not be anonymous. Possible causes: fat-arrow functions, uglify. To fix, pass a unique name as a second parameter after your callback.
In the stack trace it marks javascript commitSetRobotSerieID: RobotStateMod.commit(setRobotSerieID)
as the one of the possible causes...
Is there someone who has an idea?
@victorgarciaesgi I have tried to follow your Moving-Mate example - so maybe you have experienced it?
Hi there,
vuex-typex is a great tool to provide typings to store methods, but it seem to be not adapted to Vue 3. In Vue 3, Vue root is not global, so main Vue root object is created via createApp
in main.ts and in store/index.ts one can't just do Vue.use(Vuex)
(use
is not present in that). Instead, main.ts reads:
...
import store from './store'
createApp(App)
.use(store)
.use(router)
.mount('#app')
But without using Vue.use(Vuex)
in store/index.ts going like
import { Store } from 'vuex'
import { getStoreBuilder } from 'vuex-typex'
import { UserState } from './modules/user'
export interface RootState {
user: UserState
}
const store: Store<RootState> = getStoreBuilder<RootState>().vuexStore();
export default store
gives a runtime error "[vuex] must call Vue.use(Vuex) before creating a store instance"; moreover, TS gives a compile-time error:
const store: Store
Property 'install' is missing in type 'import("/node_modules/vuex-typex/node_modules/vuex/types/index").Store<import("/src/store/index").RootState>' but required in type 'import("/node_modules/vuex/types/index").Store<import("/src/store/index").RootState>'.ts(2741)
index.d.ts(18, 3): 'install' is declared here.
How can I fix this? Is support of Vue3 available or it requires updating Vuex-typex itself?
When creating a module with getModuleBuilder().module('namespace')
I can provide initial state to the module, however, when providing the store root with initial state by calling using builder.vuexModule({ state: initialRootState })
do I also have to provide the initial module state here?
Are there differences in providing the state through the module itself or through the root? And which one "wins" if I provide both but with different values?
Calling metrics.getMetricsDesc();
which is defined as:
import Vue from 'vue';
import Vuex, { Store } from 'vuex';
import { getStoreBuilder } from 'vuex-typex';
import { MetricsState } from './metricsState';
export interface RootState {
metrics: MetricsState
}
Vue.use(Vuex);
const store: Store<RootState> = getStoreBuilder<RootState>().vuexStore();
export { store };
export default store;
import { RootState } from './store';
import { getStoreBuilder } from 'vuex-typex';
const initialMetricsState: MetricsState = {
allMetrics: [],
isLoading: false
}
const builder = getStoreBuilder<RootState>().module('metrics', initialMetricsState);
const metricsDesc = builder.read(state => state.allMetrics.sort((a, b) => (a.date > b.date ? -1 : 1)), 'metricsDesc');
const metrics = {
// State
get state() { return builder.state(); },
// Getter as method
getMetricsDesc() {
return metricsDesc();
},
}
Just updated the dependencies on a site template which includes vuex-typex. No problems before, but now getting the following:
warning in ./node_modules/vuex-typex/dist/index.js
System.register is not supported by webpack.
Great little library - thanks for making this! 💯
I am now trying to figure out how to mock the store for testing. In vue-test-utils docs it talks about creating a store by instantiating a Vuex.Store
and setting up a localVue instance. However, with vuex-typex we use StoreBuilder.vuexStore()
instead to create a store and then call the modules' strongly typed functions rather than Vuex.Store
methods.
My goal is to be able to
jest.fn
) for call verificationHas anyone figured out how to do this with vuex-typex? I think I know how setting initial state and asserting state would work, but I am not sure how to pass in mock actions/getters for given module(s) to the store.
Also, what would be the "best" way to unit test the store's actions/getters/mutations themselves?
It would be great if plugins could be inserted into StoreBuilder.vuexStore()
export interface StoreBuilder<R> {
/** Get a ModuleBuilder for the namespace provided */
module<S>(namespace: string, state: S): ModuleBuilder<S, R>;
/** Output a Vuex Store after all modules have been built */
vuexStore(plugins: Array<(store:Store<R>) => void>): Store<R>;
}
I've tried a lot to solve that problem but I simply can't get it to work, I'm not sure if it is an issue in vue-typex or I am just too stupid to figure out whats going on.
If I use vuex-typex with IE11 it blows up with the issue described here
SCRIPT5022: Vuex handler functions must not be anonymous. Possible causes: fat-arrow functions, uglify. To fix, pass a unique name as a second parameter after your callback.
I've prepared a repro here. Any help would be awesome.
Thanks
I have this mutation
showLogin(state: ILoginState, route?: string)
But a payload is required when a call it!
Time to update to the next version of vuex.
Are you able to publish a new version with the sourcemap for dist/index.js included?
Thanks
Hi, amazing work here, but Vue / Vuex updated with new typescript "features". And your lib isnt compatible with it now.
From your documentation it seems this is a pattern, and as such I can't find any export I can use in a plugins context in nuxt.config.js, and since I'm just starting out With TypeScript I have no clue, except looking at code from different repositories, and Learning TypeScriptl
I hope you can advise on how to use it with Nuxt.
I'm having an issue with the examples in this library and my own code. I was hoping someone could ellucidate what I might be doing wrong:
When I try to use the examples in this repo I run into an issue with dispatch:
Argument of type '(context: ActionContext<any, RootState>, payload: any) => void' is not assignable to parameter of type 'ActionHandler<any, RootState, any, void>'.
Types of parameters 'context' and 'context' are incompatible.
Type 'BareActionContext<any, RootState>' is not assignable to type 'ActionContext<any, RootState>'.
Property 'dispatch' is missing in type 'BareActionContext<any, RootState>'.
I'm wondering if you have run into this problem in your own work? It's keeping me from making effective use of the library. It only happens when I type the context in an action:
function addAppError(context: StatContext, payload) {
And the dispatch: builder.dispatch(addAppError)
. Even though the builder is made correctly:
const builder = storeBuilder.module<IStatsState>(moduleName, statsStoreState);
type StatContext = ActionContext<IStatsState, RootState>;
Any thoughts? I see the same error if I try the basket example from this repo.
Our application has its own namespacing setup with Vuex modules and I'm wondering if there is a way to skip namespacing in your setup?
I have a hard time understanding my issue. I already experienced it in the past but cannot exactly remember how I got rid of it. Now again, I get a [vuex] unknown action type: attributes/getAttributes
error out of the blue without even having touched any store related code. Potentially I re-added my npm packages/package-lock.json before it happened but that's just a guess as I don't know anything else that may have changed "fundamentally".
loadData() {
console.log(attributesDispatch) // #1
console.log(attributesDispatch.getAttributes()) // #2
attributesDispatch.getAttributes() // #3
}
resulting in
{ getAttributes: ƒ }
getAttributes: ƒ (payload)
// contents:
arguments: (...)
caller: (...)
length: 1
name: ""
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: index.js?fb46:86
[[Scopes]]: Scopes[5]
0: Closure (ModuleBuilderImpl.dispatch) {_this: ModuleBuilderImpl, namespacedKey: "attributes/getAttributes"}
1: Closure {ModuleBuilderImpl: ƒ}
2: Closure {__extends: ƒ, __assign: ƒ, vuex_1: Module, useRootNamespace: {…}, qualifyKey: ƒ, …}
3: Closure (./node_modules/vuex-typex/dist/index.js) {__webpack_require__: ƒ, exports: {…}, module: {…}, arguments: Arguments(3)}
4: Global {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
[vuex] unknown action type: attributes/getAttributes
undefined
[vuex] unknown action type: attributes/getAttributes
It worked before and everything still works for my other store modules that are set up in the same way.
Anyone experiencing similar issues?
I don't see any examples of how to access other modules' 'commit' and 'dispatch' methods. What is a proper way of doing it?
Failed to parse source map from 'node_modules/vuex-typex/src/index.ts'
Version 3.1.6 fixed the missing source map for index.js. Now that this source map is available it is referencing src/index.ts which is not in the npm dist.
Currently there is this code: https://github.com/mrcrowl/vuex-typex/blob/master/src/index.ts#L173
Which checks if a handler has a name, and if it is a fat-arrow, you have to put a string yourself. It doesn't seem like it matters what you pass as a name, am I correct?
If this is the case, could we not put a new guid as the name instead of erroring out?
I've run into syntax errors when running Jest tests with Vue.js, Vuex, TypeScript, and vuex-typex
. I'm fairly new to working with Vue.js, TypeScript, and Jest.
It may be useful to mention that the tests in question are written directly against a Vuex store object, not a Vue component.
Here's the error output I get:
Test suite failed to run
.../node_modules/vuex-typex/dist/index.js:19
import { Store } from "vuex";
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
at Object.<anonymous> (src/store/main.ts:9:18)
...
I'm using the following versions of these tools:
"vue": "^2.5.10"
"vuex": "^3.0.0"
"typescript": "^2.6.2"
"vuex-typex": "^3.0.1"
"jest": "^21.2.1"
"jest-vue-preprocessor": "^1.3.1"
"@types/jest": "^21.1.8"
"ts-jest": "^21.2.4"
"typescript-babel-jest": "^1.0.5"
And here are the configuration settings that process test code:
.babelrc
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"]
}
}
}
package.json
...
"jest": {
"moduleFileExtensions": [
"js",
"ts",
"vue"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/mocks/file.ts",
"\\.(css|less)$": "<rootDir>/mocks/style.ts"
},
"transform": {
".*\\.(vue)$": "<rootDir>/node_modules/jest-vue-preprocessor",
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js",
".*": "<rootDir>/node_modules/babel-jest"
},
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!vuex-i18n).+\\.js$"
],
"testMatch": [
"**/?(*.)spec.ts"
],
"verbose": true
}
...
tsconfig.json
...
"jest": {
"globals": {
"ts-jest": {
"compilerOptions": {
"module": "commonjs"
},
"include": [
"./test/**/*"
]
}
}
}
...
I thought this might be some kind of compilation issue in the distribution code published to npm, so I tried manually processing the dist/index.js
file with Babel to the targets I'm using:
es2015
stage-2
"browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ]
This appeared to resolve the issue for me, but I'm only partially confident in my diagnosis. I don't see any other issues (open or closed) on this repository that would suggest others have run into this problem. I don't want to apply a misguided workaround or obscure an underlying implementation problem in my code.
I'm hoping that this is just a simple oversight or misunderstanding on my part. Can you offer any insight? Have you, or others you know, used this particular set of tools together with Jest tests? It appears that the tests for vuex-typex
were written with Mocha and Chai, but I imagine that others must be using this with Jest, too.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.