Search code examples
typescriptvue.jsphpstormpinia

Pinia $subscribe callback "mutation.payload" property giving a Typescript warning in PhpStorm


My code actually works OK, but I'm getting a Typescript warning that I don't understand.

const dashboardStore = useDashboardStore()

dashboardStore.$subscribe((mutation) => {
  // This works OK!
  console.log(mutation.payload.id)
})

PhpStorm gives me a warning on mutation.payload:

TS2339: Property 'payload' does not exist on type 'SubscriptionCallbackMutation'.   Property 'payload' does not exist on

It correctly infers that the callback itself is a Pinia SubscriptionCallback<DashboardState>.

The Pinia types show the mutation argument as type SubscriptionCallbackMutation<S>, and declares that type as:

export declare type SubscriptionCallbackMutation<S> = SubscriptionCallbackMutationDirect | SubscriptionCallbackMutationPatchObject<S> | SubscriptionCallbackMutationPatchFunction;

And of course type SubscriptionCallbackMutationPatchObject has the patch property I need.

So if I explicitly type the callback arguments...

dashboardStore.$subscribe((mutation: SubscriptionCallbackMutation<DashboardState>) => {
  // No errors or warnings
  const typedMutation = mutation as SubscriptionCallbackMutationPatchObject<DashboardState>
  console.log(mutation.payload.id)
}

But I cannot specify the mutation argument as SubscriptionCallbackMutationPatchObject<DashboardState> and that's confusing to me.

Anyone understand why? And how I can accomplish this without re-typign?


Solution

  • I realized that Pinia's type was definitively SubscriptionCallbackMutation<S>, per the declaration:

    export declare type SubscriptionCallbackMutation<S> = SubscriptionCallbackMutationDirect | SubscriptionCallbackMutationPatchObject<S> | SubscriptionCallbackMutationPatchFunction;
    

    ...But that doesn't guarantee that it will be SubscriptionCallbackMutationPatchObject<S>, and hence won't have the payload property. It's on me to verify that.

    As such, I can explicitly type the mutation param to SubscriptionCallbackMutation<DashboardState> and then just check in the method call, like this:

    dashboardStore.$subscribe(async (mutation: SubscriptionCallbackMutation<DashboardState>) => {
      const params: DashboardQueryParams = {}
      if (mutation.type === MutationType.patchObject) {
        const payload = mutation.payload
        // Do stuff now that I know it's a Patch mutation.
      }
    })