Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nuxt plugin property does not exist on type 'CombinedVueInstance

I've created a plugin and want to use it inside one of my components. The code from the plugin located under ~/plugins/socket.client.ts:

import { io } from 'socket.io-client'
import { Plugin } from '@nuxt/types'

const socketIOPlugin: Plugin = (_, inject) => {
  const socketUrl: string | undefined = process.env.socket_url

  if (!socketUrl || socketUrl.length <= 0) {
    throw new Error('socketUrl is undefined.')
  }

  const socket = io(socketUrl)
  inject('socket', socket)
}

export default socketIOPlugin

It is registered inside the nuxt.config.js. plugins: ['~/plugins/socket.client']

And I use it inside my component like this:

import Vue from 'vue'

export default Vue.extend({
  mounted() {
    this.$socket.on("example:hello", (data: any) => {
      console.log(data);
    });
  },
})

However, when I start nuxt, I get the following error: Property '$socket' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.

I've already tried adding a vue-shim.d.ts file, but still nothing changes.

declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}

declare module "vue/types/vue" {
  import { Socket } from "socket.io-client";
  interface Vue {
    $socket: Socket;
  }
}

I can't seem to find a way to solve this. Can anyone please help me?

like image 224
Tjeu Foolen Avatar asked Oct 29 '25 09:10

Tjeu Foolen


1 Answers

I've finally got it working by refactoring my code a bit.

Disclaimer; This solution works for me because it lets me use the plugin in another way. It is not specifically the answer to the question. The answer to this question can be achieved by using the plugin code from below and change the index.d.ts a bit so the $socket is also accessible inside the vue components. Read more about this here.

~/plugins/socket.client.ts

import { Plugin } from '@nuxt/types'
import { io, Socket } from 'socket.io-client'

function getSocketConnection(): Socket {
  const socketUrl: string | undefined = process.env.socket_url

  if (!socketUrl || socketUrl.length <= 0) {
    throw new Error('socketUrl is undefined.')
  }

  return io(socketUrl)
}

const socketIOPlugin: Plugin = (_, inject) => {
  inject('socket', getSocketConnection())
}

export default socketIOPlugin
export const socket = getSocketConnection()

I've also renamed vue-shim.d.ts to just index.d.ts and added the following lines:

import { accessorType } from '~/store'
import { socket } from '~/plugins/socket.client'

declare module 'vuex/types/index' {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface Store<S> {
    $socket: typeof socket
  }
}

declare module 'vue/types/vue' {
  interface Vue {
    $accessor: typeof accessorType
  }
}

declare module '@nuxt/types' {
  interface NuxtAppOptions {
    $accessor: typeof accessorType
  }
}

Instead of using the socket.io plugin inside my components, I've created a store ~/store/index.ts that handles all socket events.

import type { ActionTree, GetterTree, MutationTree } from 'vuex'
import { getAccessorType } from 'typed-vuex'

export const state = () => ({
  posts: [] as any[],
})

export type RootState = ReturnType<typeof state>

export const getters: GetterTree<RootState, RootState> = {
  posts: (state) => state.posts,
}

export const mutations: MutationTree<RootState> = {
  SET_POSTS: (state: RootState, posts: any[]) => (state.posts = posts),
}

export const actions: ActionTree<RootState, RootState> = {
  fetchPosts({ commit }) {
    this.$socket.emit('example:getPosts')
    this.$socket.once('example:posts', (data: any) => {
      commit('SET_POSTS', data)
    })
  },
}

export const accessorType = getAccessorType({
  state,
  getters,
  mutations,
  actions,
  modules: {},
})

The usage is now a lot easier and everything updates how it is ment to be with vuex.

~/pages/index.vue

<script lang='ts'>
import { Component, Vue } from 'nuxt-property-decorator'

@Component
export default class Index extends Vue {
  get posts() {
    return this.$accessor.posts
  }

  fetchPosts() {
    this.$accessor.fetchPosts()
  }
}
</script>

To get everything to work you need to install the following npm packages:

  • @nuxt/types
  • typed-vuex
  • vue-class-component
  • nuxt-property-decorator
  • nuxt-typed-vuex (Do not forget to add this to your nuxt.config.ts buildModules)
like image 166
Tjeu Foolen Avatar answered Nov 01 '25 00:11

Tjeu Foolen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!