Skip to content

feat(types): expose store options to plugins via PiniaCustomOptionsProperties - #3174

Open
haoku123 wants to merge 1 commit into
vuejs:v4from
haoku123:feat/pinia-custom-options-properties
Open

feat(types): expose store options to plugins via PiniaCustomOptionsProperties#3174
haoku123 wants to merge 1 commit into
vuejs:v4from
haoku123:feat/pinia-custom-options-properties

Conversation

@haoku123

Copy link
Copy Markdown

Problem

Closes #1247

Plugins can add custom options through DefineStoreOptionsBase (module augmentation) and read them in the plugin callback via context.options, but there is no way to type properties returned by the plugin from those options. PiniaCustomProperties only receives Id, S, G, A — the options type is never threaded into the store type, so this.stores (or any other option-derived property) can only be typed with the widest Store/Record types.

Solution

Add a dedicated PiniaCustomOptionsProperties<O> interface intersected into Store, mirroring the existing PiniaCustomProperties pattern:

export interface PiniaCustomOptionsProperties<O = _Empty> {}

The resolved options of each store flow into O without any change to user-facing signatures: defineStore returns StoreDefinition<Id, S, G, A, DefineStoreOptions<Id, S, G, A>> (and the setup overload passes DefineSetupStoreOptions), StoreDefinition and SetupStoreDefinition forward O, and Store intersects PiniaCustomOptionsProperties<O>. O defaults to _Empty, so existing code that writes Store<Id, S, G, A> or StoreGeneric is unaffected.

The plugin from the issue then works with full typing:

declare module 'pinia' {
  export interface DefineStoreOptionsBase<S, Store> {
    stores?: Record<string, StoreDefinition>
  }

  export interface PiniaCustomOptionsProperties<O> {
    readonly stores: O extends { stores?: infer Stores }
      ? { [K in keyof Stores]: Stores[K] extends StoreDefinition
          ? ReturnType<Stores[K]>
          : never
        }
      : Record<string, Store>
  }
}

mapStores is updated so _StoreObject keeps the options type through its StoreDefinition inference (previously the 4-parameter infer would have silently dropped O, losing the plugin properties on mapped stores).

Tests

Added test-dts/storeOptions.test-d.ts recreating the #1247 plugin scenario: custom stores/marker options declared through augmentation are resolved on the store instance, with and without the custom options. Full suite passes: pnpm run test:types, pnpm run test:dts, and pnpm run test:vitest run (260 tests).

Notes

This is type-only: no runtime changes. The earlier attempt at #3042 (closed) added a runtime _options field; this approach keeps everything at the type level, matching how PiniaCustomProperties already works.

…operties

Plugins adding properties through PiniaCustomProperties cannot type
them from the options passed to defineStore(), because the options
type is never threaded into the store type. Add a
PiniaCustomOptionsProperties<O> interface intersected into Store,
carrying the resolved store options (including custom options declared
on DefineStoreOptionsBase through module augmentation), and pass it
through defineStore/StoreDefinition/SetupStoreDefinition.

mapStores keeps the options type through _StoreObject so mapped stores
preserve the plugin properties.

Closes vuejs#1247
@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for pinia-playground ready!

Name Link
🔨 Latest commit e8febc7
🔍 Latest deploy log https://app.netlify.com/projects/pinia-playground/deploys/6a7f472ad0a44e00081b75e6
😎 Deploy Preview https://deploy-preview-3174--pinia-playground.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for pinia-official canceled.

Name Link
🔨 Latest commit e8febc7
🔍 Latest deploy log https://app.netlify.com/projects/pinia-official/deploys/6a7f472a3a238300085f5a98

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b424b838-cbea-480c-a584-fbd5075a73ad

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@haoku123
haoku123 changed the base branch from v3 to v4 August 14, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🆕 Triaging

Development

Successfully merging this pull request may close these issues.

Plugins: Expose DefineStoreOptionsBase in PiniaCustomProperties

1 participant