Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Typescript is losing the this type, causing injection to not work #508

Closed

Description

@Caceresenzo

Describe the bug

Typescript is 'losing' the this type.

I think this will solve the common issue where this.$axios is not working in the store.

To Reproduce
Steps to reproduce the behavior:

  1. Create a basic nuxt typescript project (with axios plugin)
  2. Add the following code in store/index.js
import { Store, ActionTree, ActionContext } from 'vuex'

export const state = () => ({
  hello: 'world',
})

export type RootState = ReturnType<typeof state>

export type UserActionContext = ActionContext<RootState, RootState>

export interface UsersActions extends ActionTree<RootState, RootState> {

  // with specified 'this' type (work fine)
  fetchAll(this: Store<RootState>, context: UserActionContext): Promise<void>
  
  // without specified 'this' type (work but do not compile)
  second(context: UserActionContext): Promise<void>
  
}

export const actions: UsersActions = {
  async fetchAll(context) {
    await this.$axios.$get('/users')

    console.log(this.constructor.name)
  },

  async second(context) {
    await this.$axios.$get('/users')

    console.log(this.constructor.name)
  },
}
  1. See error
ERROR in store/index.ts:27:23
TS2339: Property '$get' does not exist on type 'Action<{ hello: string; }, { hello: string; }>'.
  Property '$get' does not exist on type 'ActionHandler<{ hello: string; }, { hello: string; }>'.
    25 |
    26 |   async second(context) {
  > 27 |     await this.$axios.$get('/users')
       |                       ^^^^
    28 |
    29 |     console.log(this.constructor.name)
    30 |   },

Expected behavior

To compile without any problem.

Since with its work (compile) fine...

export const actions2: ActionTree<RootState, RootState> = {
  async fetchAll(context) {
    await this.$axios.$get('/users')

    console.log(this.constructor.name)
  },
}

Additional context

The this is a effectively a Store.
'Provable' with:

await this.$store.dispatch('fetchAll')
await this.$store.dispatch('second')

(it will print 'Store' x 2)

EDIT: Removed screenshot section

Activity

  1. rchl commented on Mar 13, 2023

    @rchl
    Collaborator

    It appears to me that when you are explicitly defining the custom actions with:

    export interface UsersActions extends ActionTree<RootState, RootState> {
      // with specified 'this' type (work fine)
      fetchAll: (this: Store<RootState>, context: UserActionContext) => Promise<void>
      // without specified 'this' type (work but do not compile)
      second(context: UserActionContext): Promise<void>
    }

    then Typescript is then not able to match those against the interface defined by vuex:

    export interface ActionTree<S, R> {
      [key: string]: Action<S, R>;
    }

    And treats them as different interface properties with their own types.
    If you skip your custom declarations like so:

    export interface UsersActions extends ActionTree<RootState, RootState> {}

    then this will be correctly inferred in the actual methods.

    Vuex is known for not being very type-friendly so I'm not sure if there is better solution than what you found yourself (explicitly specifying this).

  2. locked and limited conversation to collaborators on Mar 14, 2023
  3. converted this issue into a discussion #569 on Mar 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions