The property 'Nuxt plugin' is not recognized in the 'CombinedVueInstance' type

I have developed a custom plugin and I want to integrate it into one of my components. The code for the plugin is stored in ~/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

The plugin is added to the nuxt.config.js file as follows:

plugins: ['~/plugins/socket.client']

Then, I utilize the plugin in my component like this:

import Vue from 'vue'

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

However, upon starting nuxt, I encounter the following error message:

Property '$socket' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.

I've attempted creating a vue-shim.d.ts file without success.

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 am struggling to find a solution to this issue. Can someone please provide assistance?

Answer №1

After some code refactoring, I finally managed to get it working.

Important Note: While this solution works for me by enabling usage of the plugin in a different manner, it may not directly address the original question. To achieve the desired outcome, consider modifying the index.d.ts file slightly so that $socket becomes accessible within the Vue components. For more information on this, refer 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 also renamed vue-shim.d.ts to 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 directly using the socket.io plugin within components, I've created a store at ~/store/index.ts to handle 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: {},
})

This approach has made usage much simpler and ensured everything updates correctly 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 ensure everything functions properly, be sure to install the necessary npm packages listed below:

Answer №2

When creating a module under the declaration of "vue/types/vue"
, it is considered a form of module augmentation. To ensure proper functionality, this code must be placed within a TS file that includes at least one top-level import/export statement (more information can be found here)

Therefore, I recommend transferring this code from vue-shim.d.ts directly into socket.client.ts

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you explain how the functionality of `v-b-modal` and `v-b-toggle` attributes operate and where they are monitored?

I'm trying to figure out how to add a custom attribute that triggers events, similar to the ones in this example. However, I can't seem to understand how they function. For instance: <b-button v-b-modal.modal-1>Launch demo modal</b-but ...

Unraveling the Mystery of @Input and @Output Aliases in Angular 2

After researching about the @Input() and @Output() decorators, I discovered that we have the option to use an alias instead of the property name for these decorators. For example: class ProductImage { //Aliased @Input('myProduct') pro ...

Function Type Alias with No Particular Name

Have you ever wondered why in TypeScript type alias doesn't work with a generic function? Take for example the scenario where TS fails to define type Identical as generic. type Identical = <T>(v: T) => T; const identical: Identical<strin ...

Cypress Vue Component Test Runner - verifying that clicking a button triggers an event

I'm struggling to figure out how to conduct a basic test on a Vue component (using the Cypress Component Test Runner) in order to verify if clicking a button emits an event // MyButton.vue component <template> <Button data-t ...

The V-Model is refusing to be updated

After creating a simple Datatable with a search input functionality, Student.js Vue.component('student-list',{ props: ['students'], template:` <div class="table-responsive"> <table class="table table-hover mails m-0 ...

Issue with calling function from props in React is not being resolved

There seems to be an issue with the function not being called when passed into a functional component. While the onSubmit function is triggered, the login(email, password) function inside the Login component is never executed. Despite placing console.log s ...

Implementing a onClick event to change the color of individual icons in a group using Angular

I have integrated 6 icons into my Angular application. When a user clicks on an icon, I want the color of that specific icon to change from gray to red. Additionally, when another icon is clicked, the previously selected icon should revert back to gray whi ...

Verification of unique custom string

How can I ensure that a string follows the specific format of x.xx.xxxxx? The first character is mandatory, followed by a period, then two characters, another period, and finally any number of characters of varying lengths. ...

Tips for effectively managing and storing data from a modal in Angular 12 beyond just the ID

I will provide an example to clarify my question as I am struggling to find a better way to phrase it. Here are the interfaces I am working with : import { Product } from "./product.model"; import { User } from "./user.model"; export ...

How to utilize ngFor for multiple inputs in Angular 4

Apologies for my poor English, I'll do my best to explain my issue. Here's the problem: I'm using ngFor on an Input element, but when I enter data, it gets repeated in all the fields and I can't figure out why. <div *ngFor=" ...

"Utilizing a Node server in conjunction with the Vue Vite bundler: A comprehensive

Is there a way to utilize Node.js server instead of Vite's own frontend development server on port 3000? I've attempted different command combinations, such as: vite vite preview vite preview --port:5000 Thank you. UPDATE February 8th, 2022 I ...

I am having trouble retrieving images from the backend API. Can someone assist me in resolving this issue?

I am facing an issue while trying to upload an image along with its details. I am able to retrieve all the information but the image is not displaying in the browser. My backend API is built using PHP Laravel and the images are stored in the Storage/app/ap ...

VueDraggable: enabling cloning exclusively

Here is an example to illustrate the point: Let's say we have a shopping website where "Draggable 1" represents the items available for purchase and "Draggable 2" represents the user's shopping cart. Users should be able to drag items from ...

Is there a way to showcase the data of each table row within the tr tag in an Angular 8 application?

I have been developing an application using Angular 8. The employee-list component is responsible for presenting data in a table format. Within the employee-list.component.ts file, I have defined: import { Component } from '@angular/core'; impo ...

Can you retrieve the Angular Service Instance beyond the scope of an angular component?

Is it possible to obtain the reference of an Injectable Angular service within a generic class without including it in the constructor? I am exploring different methods to access the Service reference. For example: export class Utils { getData(): string ...

Converting the Angular Material Select Demo Stackblitz into a Self-Contained Component?

Attempting to transform the Angular Material Select Demo into a self-contained component. Check out the Stackblitz here. Here are the necessary steps: Replace main.ts with the following (To create standalone component): import { bootstrapApplication } f ...

Having trouble pushing to an array in Angular typescript? It seems to be returning as undefined

As a newcomer to Angular with a basic understanding of JavaScript, I am attempting to create a program that can solve Sudoku puzzles. In a 9x9 grid, there are a total of 81 points or squares. To efficiently check for violations of Sudoku rules - no repeati ...

"Maximizing Performance with Vue.js Keep-Alive and Efficient Event Rendering

I am working with 1 master component and 2 child components. In the master component, I have the following code: <keep-alive> <component :is="getChild" @onrender="childRender" /> </keep-alive> This setup allows me to switch betw ...

Can you please explain the process of implementing server-side rendering with React?

During my work, I utilized Node's express for sever side rendering with React. However, an unexpected error occurred as shown below. ^ SyntaxError: Unexpected token '<' This particular error popped up unexpectedly. I reached ou ...

Is TypeScript the ultimate solution for function typing?

Currently delving into TypeScript, and I've got a query regarding annotating function types. Taking a look at this basic example: export const add = (num1: number, num2: number):number => { return num1 + num2; }; This seems well-typed to me. Ty ...