Skip to content

Basic Example

A basic generic store and a store that extends it.

Generic Store

Store type

ts
type ProductStore<T> = PiniaStore<'product', {
  all: T[]
}, {
  getTotal: () => number
  getMaxPrice: () => number
}, {
  add: (item: T) => void
}>
ts
interface ProductState<T> {
  all: T[]
}

interface ProductGetters {
  getTotal: () => number
  getMaxPrice: () => number
}

interface ProductActions<T> {
  add: (item: T) => void
}

type ProductStore<T> = PiniaStore<'product', ProductState<T>, ProductGetters, ProductActions<T>>

Store function

ts
function productStore<T extends Book>() {
  return defineGenericStore<ProductStore<T>>({
    state: {
      all: [],
    },
    getters: {
      getTotal() {
        return this.all.reduce((total, item) => total + item.price, 0)
      },
      getMaxPrice() {
        return this.all.reduce((max, item) => Math.max(max, item.price), 0)
      },
    },
    actions: {
      add(item: T) {
        this.all.push(item)
      },
    },
  })
}
ts
function productState<T>() {
  return createState<ProductStore<T>>({
    all: [],
  })
}

function productGetters<T extends Book>() {
  return createGetters<ProductStore<T>>({
    getTotal() {
      return this.all.reduce((total, item) => total + item.price, 0)
    },
    getMaxPrice() {
      return this.all.reduce((max, item) => Math.max(max, item.price), 0)
    },
  })
}

function productActions<T>() {
  return createActions<ProductStore<T>>({
    add(item: T) {
      this.all.push(item)
    },
  })
}

function productStore<T extends Book>() {
  return defineGenericStore<ProductStore<T>>({
    state: productState<T>(),
    getters: productGetters<T>(),
    actions: productActions<T>(),
  })
}

Using the Generic Store

Type that will go in the place of T.

ts
interface Book {
  id: number
  name: string
  price: number
}

Store type

ts
type BookStore = PiniaStore<'book', {
  active: Book | null
}, {
  getAveragePrice: () => number
}, object, ProductStore<Book>>
ts
interface BookState {
  active: Book | null
}

interface BookGetters {
  getAveragePrice: () => number
}

type BookStore = PiniaStore<'book', BookState, BookGetters, object, ProductStore<Book>>

Creating the store

ts
export const useBookStore = useStore<BookStore, ProductStore<Book>>('book', {
  state: {
    active: null,
    all: [
      { id: 1, name: 'The Lord of the Rings', price: 20 },
      { id: 2, name: 'The Hitchhiker\'s Guide to the Galaxy', price: 42 },
      { id: 3, name: 'The Little Prince', price: 10 },
    ],
  },
  getters: {
    getAveragePrice() {
      return this.getTotal / this.all.length
    },
  },
}, productStore<Book>(),)
ts
const bookState = createState<BookStore, ProductStore<Book>>({
  active: null,
  all: [
    { id: 1, name: 'The Lord of the Rings', price: 20 },
    { id: 2, name: 'The Hitchhiker\'s Guide to the Galaxy', price: 42 },
    { id: 3, name: 'The Little Prince', price: 10 },
  ],
})

const bookGetters = createGetters<BookStore, ProductStore<Book>>({
  getAveragePrice() {
    return this.getTotal / this.all.length
  },
})

export const useBookStore = useStore<BookStore, ProductStore<Book>>('book', {
  state: bookState,
  getters: bookGetters,
}, productStore<Book>(),)

Resulting Store

basic store