CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pinia

Intuitive, type safe and flexible Store for Vue

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

options-api.mddocs/

Options API Integration

Map helper functions that provide compatibility with Vue's Options API, allowing stores to be mapped to component computed properties and methods.

Capabilities

Map Stores

Maps multiple stores to component computed properties, providing access to store instances via this.

/**
 * Maps multiple stores to component computed properties
 * @param stores - Array of store definitions to map
 * @returns Object with store accessor computed properties
 */
function mapStores<Stores extends any[]>(...stores: [...Stores]): _Spread<Stores>;

type _Spread<A extends readonly any[]> = A extends readonly [infer L, ...infer R]
  ? _StoreObject<L> & _Spread<R>
  : unknown;

type _StoreObject<S> = S extends StoreDefinition<infer Id, infer State, infer Getters, infer Actions>
  ? {
      [K in `${Id}${MapStoresCustomization extends Record<'suffix', infer Suffix>
        ? Suffix
        : 'Store'}`]: () => Store<Id, State, Getters, Actions>
    }
  : {};

Usage Examples:

import { mapStores } from "pinia";
import { useUserStore } from "./stores/user";
import { useCartStore } from "./stores/cart";
import { useProductStore } from "./stores/product";

export default {
  computed: {
    // Maps stores to computed properties ending with "Store"
    ...mapStores(useUserStore, useCartStore, useProductStore),
  },
  methods: {
    handlePurchase() {
      // Access stores via computed properties
      this.userStore.updateLastPurchase();
      this.cartStore.clear();
      this.productStore.decreaseInventory(this.cartStore.items);
    },
  },
};

// Custom suffix
import { setMapStoreSuffix } from "pinia";
setMapStoreSuffix("Repository");

export default {
  computed: {
    ...mapStores(useUserStore), // Creates userRepository computed property
  },
};

Map State

Maps store state properties to component computed properties, providing reactive access to state values.

/**
 * Maps store state properties to component computed properties
 * @param useStore - Store definition to map from
 * @param keys - Array of state property keys to map
 * @returns Object with reactive computed properties
 */
function mapState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  Keys extends keyof (S & G)
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keys: readonly Keys[]
): _MapStateReturn<S & G, Keys>;

/**
 * Maps store state properties with custom names or functions
 * @param useStore - Store definition to map from  
 * @param keysObject - Object mapping local names to store properties or functions
 * @returns Object with reactive computed properties
 */
function mapState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysObject: Record<string, keyof (S & G) | ((store: Store<Id, S, G, A>) => any)>
): _MapStateObjectReturn<Id, S, G, A>;

type _MapStateReturn<T, Keys extends keyof T> = {
  [K in Keys]: () => T[K];
};

type _MapStateObjectReturn<Id extends string, S extends StateTree, G, A> = Record<
  string,
  () => any
>;

Usage Examples:

import { mapState } from "pinia";
import { useCounterStore } from "./stores/counter";
import { useUserStore } from "./stores/user";

export default {
  computed: {
    // Simple array mapping
    ...mapState(useCounterStore, ["count", "doubleCount"]),
    ...mapState(useUserStore, ["currentUser", "isLoggedIn"]),
    
    // Object mapping with custom names
    ...mapState(useUserStore, {
      user: "currentUser",
      loggedIn: "isLoggedIn",
      username: (store) => store.currentUser?.name || "Guest",
    }),
    
    // Mixed usage
    ...mapState(useCounterStore, {
      currentCount: "count",
      isEven: (store) => store.count % 2 === 0,
    }),
  },
  template: `
    <div>
      <p>Count: {{ count }}</p>
      <p>Double: {{ doubleCount }}</p>
      <p>User: {{ username }}</p>
      <p>Even: {{ isEven }}</p>
    </div>
  `,
};

Map Writable State

Maps store state properties as writable computed properties, allowing two-way binding with v-model.

/**
 * Maps store state properties as writable computed properties
 * @param useStore - Store definition to map from
 * @param keys - Array of state property keys to map as writable
 * @returns Object with writable computed properties
 */
function mapWritableState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  Keys extends keyof S
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keys: readonly Keys[]
): _MapWritableStateReturn<S, Keys>;

/**
 * Maps store state properties as writable with custom names
 * @param useStore - Store definition to map from
 * @param keysObject - Object mapping local names to store state properties
 * @returns Object with writable computed properties
 */
function mapWritableState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysObject: Record<string, keyof S>
): _MapWritableStateObjectReturn<S>;

type _MapWritableStateReturn<S, Keys extends keyof S> = {
  [K in Keys]: {
    get(): S[K];
    set(value: S[K]): void;
  };
};

type _MapWritableStateObjectReturn<S> = Record<string, {
  get(): any;
  set(value: any): void;
}>;

Usage Examples:

import { mapWritableState } from "pinia";
import { useFormStore } from "./stores/form";
import { useSettingsStore } from "./stores/settings";

export default {
  computed: {
    // Direct writable mapping
    ...mapWritableState(useFormStore, ["name", "email", "message"]),
    
    // Custom names
    ...mapWritableState(useSettingsStore, {
      darkMode: "isDarkMode",
      lang: "language",
    }),
  },
  template: `
    <form>
      <!-- Two-way binding with store state -->
      <input v-model="name" placeholder="Name" />
      <input v-model="email" placeholder="Email" />
      <textarea v-model="message" placeholder="Message"></textarea>
      
      <!-- Settings -->
      <label>
        <input type="checkbox" v-model="darkMode" />
        Dark Mode
      </label>
      <select v-model="lang">
        <option value="en">English</option>
        <option value="es">Spanish</option>
      </select>
    </form>
  `,
};

Map Getters

Maps store getters to component computed properties. This is an alias for mapState but specifically for getters.

/**
 * Maps store getters to component computed properties
 * @param useStore - Store definition to map from
 * @param keys - Array of getter keys to map
 * @returns Object with reactive computed properties
 */
function mapGetters<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  Keys extends keyof G
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keys: readonly Keys[]
): _MapStateReturn<G, Keys>;

Usage Examples:

import { mapGetters } from "pinia";
import { useCounterStore } from "./stores/counter";

export default {
  computed: {
    ...mapGetters(useCounterStore, ["doubleCount", "isEven", "displayName"]),
  },
  template: `
    <div>
      <p>Double Count: {{ doubleCount }}</p>
      <p>Is Even: {{ isEven ? 'Yes' : 'No' }}</p>
      <p>Display: {{ displayName }}</p>
    </div>
  `,
};

Map Actions

Maps store actions to component methods, providing direct access to store methods.

/**
 * Maps store actions to component methods
 * @param useStore - Store definition to map from
 * @param keys - Array of action keys to map
 * @returns Object with action methods
 */
function mapActions<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  Keys extends keyof A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keys: readonly Keys[]
): _MapActionsReturn<A, Keys>;

/**
 * Maps store actions with custom names
 * @param useStore - Store definition to map from
 * @param keysObject - Object mapping local names to action names
 * @returns Object with action methods
 */
function mapActions<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysObject: Record<string, keyof A>
): _MapActionsObjectReturn<A>;

type _MapActionsReturn<A, Keys extends keyof A> = {
  [K in Keys]: A[K];
};

type _MapActionsObjectReturn<A> = Record<string, any>;

Usage Examples:

import { mapActions } from "pinia";
import { useCounterStore } from "./stores/counter";
import { useUserStore } from "./stores/user";

export default {
  methods: {
    // Direct action mapping
    ...mapActions(useCounterStore, ["increment", "decrement", "reset"]),
    
    // Custom names
    ...mapActions(useUserStore, {
      signIn: "login",
      signOut: "logout",
      updateProfile: "updateUser",
    }),
    
    // Use in component methods
    handleIncrement() {
      this.increment(); // Calls store action
    },
    
    async handleLogin() {
      try {
        await this.signIn({ email: this.email, password: this.password });
        this.$router.push("/dashboard");
      } catch (error) {
        this.showError(error.message);
      }
    },
  },
  template: `
    <div>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
      <button @click="reset">Reset</button>
      <button @click="handleLogin">Login</button>
    </div>
  `,
};

Set Map Store Suffix

Customizes the suffix used by mapStores when creating computed property names.

/**
 * Sets the suffix for store names in mapStores
 * @param suffix - New suffix to use (default is "Store")
 */
function setMapStoreSuffix(suffix: string): void;

interface MapStoresCustomization {
  suffix?: string;
}

Usage Examples:

import { setMapStoreSuffix, mapStores } from "pinia";
import { useUserStore } from "./stores/user";

// Default behavior
export default {
  computed: {
    ...mapStores(useUserStore), // Creates 'userStore' computed property
  },
};

// Custom suffix
setMapStoreSuffix("Repository");

export default {
  computed: {
    ...mapStores(useUserStore), // Creates 'userRepository' computed property
  },
};

// Empty suffix
setMapStoreSuffix("");

export default {
  computed: {
    ...mapStores(useUserStore), // Creates 'user' computed property
  },
};

// Reset to default
setMapStoreSuffix("Store");

Complete Options API Example

import { mapStores, mapState, mapWritableState, mapActions } from "pinia";
import { useCounterStore } from "./stores/counter";
import { useUserStore } from "./stores/user";
import { useCartStore } from "./stores/cart";

export default {
  computed: {
    // Store instances
    ...mapStores(useCounterStore, useUserStore, useCartStore),
    
    // Read-only state
    ...mapState(useCounterStore, ["count", "doubleCount"]),
    ...mapState(useUserStore, ["currentUser", "isLoggedIn"]),
    
    // Writable state for forms
    ...mapWritableState(useUserStore, ["email", "preferences"]),
    
    // Custom computed
    canPurchase() {
      return this.isLoggedIn && this.cartStore.items.length > 0;
    },
  },
  
  methods: {
    // Store actions
    ...mapActions(useCounterStore, ["increment", "reset"]),
    ...mapActions(useUserStore, {
      signIn: "login",
      signOut: "logout",
    }),
    ...mapActions(useCartStore, ["addItem", "removeItem", "checkout"]),
    
    // Component methods
    async handleCheckout() {
      if (this.canPurchase) {
        await this.checkout();
        this.reset(); // Reset counter after purchase
      }
    },
  },
  
  template: `
    <div>
      <p>Count: {{ count }} ({{ doubleCount }})</p>
      <button @click="increment">+</button>
      
      <div v-if="isLoggedIn">
        <p>Welcome {{ currentUser.name }}!</p>
        <input v-model="email" placeholder="Email" />
        <button @click="handleCheckout" :disabled="!canPurchase">
          Checkout
        </button>
      </div>
      
      <button v-else @click="signIn">Sign In</button>
    </div>
  `,
};

Types

type _GettersTree<S extends StateTree> = Record<
  string,
  ((state: UnwrapRef<S> & UnwrapRef<PiniaCustomStateProperties>) => any) | (() => any)
>;

Install with Tessl CLI

npx tessl i tessl/npm-pinia

docs

index.md

options-api.md

pinia-instance.md

store-definition.md

store-usage.md

tile.json