Home > Back-end >  How do i properly use pinia store on Vue3 Pinia Typescript
How do i properly use pinia store on Vue3 Pinia Typescript

Time:10-12

I struggle on using Pinia store with typescript and using store inside basic app.vue Vuejs3 option api.

I have this app.js file

import {createApp} from 'vue'
import {createPinia} from "pinia";

import App from './App';
const pinia = createPinia()

const app = createApp(App);

app.use(pinia);

app.mount('#app');

This app.vue

<script>
import {useAuthStore} from "@app/store/auth.store";
import {useCountryStore} from "@app/store/country.store";

export default {
  components: {SidebarMenu},
  setup() {
    return {
      authStore: useAuthStore(),
      countryStore: useCountryStore(),
    }
  },
  computed: {
    loggedIn: function () {
      return this.authStore.status.loggedIn;
    }
  }
}
</script>

This authStore.js :

import {defineStore} from "pinia";

const user = JSON.parse(localStorage.getItem('user'));

export const useAuthStore = defineStore("auth", {
    state: () => (
        user ? {status: {loggedIn: true}, user}  : {status: {loggedIn: false}, user: null}
    ),
});

And this CountryStore.ts

import { defineStore } from "pinia";
import { Country } from "@app/interfaces/country";

export type CountryState = {
    countries: Country[],
    errors: any[],
}

export const useCountryStore = defineStore("country", {
    state: () => ({
        countries: [],
        errors: []
    } as CountryState)
})

In my case, no matter what i do i get this error because of countryStore but not AuthStore:

getActivePinia was called with no active Pinia. Did you forget to install pinia?

But for whatever reason. If i turn my countryStore.ts into .js (and removing type hinting of course), it work!

I search a lot about why it does that, what i am missing or what do i do wrong.
Of course i want to keep typescript in the end but i don't know how to make it work.

Thanks to anyone who can help me. Love you all.

CodePudding user response:

Try giving the defineStore a name as a first argument then the options object as the second argument. Just as you did on your authStore.

from:

export const useCountryStore = defineStore( {
    id: "country",
    state: () => ({
        countries: [],
        errors: []
    } as CountryState)
})

to:

export const useCountryStore = defineStore("country", {
    id: "country",
    state: () => ({
        countries: [],
        errors: []
    } as CountryState)
})

CodePudding user response:

So, i figured it out myself by trying multiple things. Nothing is wrong with Pinia.
My major issue was, i started the project without typescript and started to implement it after on "some file"

If you want to enable typescript, switch all your .js file in .ts
This is not needed for .vue
Then here is a list of various i've done to make everything work :

Use this tsconfig :

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": "./assets", //this is your working folder, usually ./ only, since i'm using webpack encore   symfony i adapted it
    "types": [
      "webpack-env"
    ],
    "paths": { // very important to make your import @app work
      "@app/*": [
        "*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "assets/**/*.ts",
    "assets/**/*.tsx",
    "assets/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

Add shims-vue.d.ts inside your main folder (/assets for me), i still dont know why this is needed but it saved me

declare module '*.vue' {
    import type { DefineComponent } from 'vue'
    const component: DefineComponent<{}, {}, any>
    export default component
}

Dont forget this when creating components

<script lang="ts">

Dont forget to turn your main.js or app.js into .ts And adapt webpack.config.js encore

.addEntry('app', './assets/app.ts')
.addAliases({
     '@app': path.resolve(__dirname, 'assets/') //usefull for @app/ in import, you can also only use @, adapt it on your desire
})

After this you will get a lot of compiled error related to things to adapat in your code.

One trick is .vue file not gonna be imported and throw "module not found"

For example, i had to switch from :

import App from './App';

To :

import App from './App.vue';

If everyone have better practice, feel free to share and i will adapt my answer

  • Related