如何在 pinia 中设置状态对象的类型?

How to set the type for the state object in pinia?

我正在制作国际象棋游戏,我正在使用 Vue 3 和 TypeScript 以及 Pinia 进行状态管理。

我想做如下事情:

export const useStore = defineStore("game", {
  state: () => {
    return {
      moves: [],
      gameBoard:  getInitialBoard(),
      playerTurn: PieceColor.White,
      previousPieceSelected: undefined
    }
  },
    updatePreviousPieceSelected(piece: Piece | undefined ) {
      this.previousPieceSelected = piece
    }
  }
})

UpdateGameState.vue

setup() {
    const store = useStore()
    const previousPieceSelected: Piece | undefined = store.previousPieceSelected;
    let playerTurn: PieceColor = store.playerTurn;

    const initialGameState: GameState = {
      boardState: store.gameBoard,
      playerTurn,
    };

    const updateGameState = (
      cellRow: number,
      cellCol: number,
      currentPiece: Piece
    ) => {
      if (
        previousPieceSelected === undefined ||
        previousPieceSelected.pieceType === PieceType.None
      ) {
        store.updatePreviousPieceSelected(currentPiece);
      }
      if (
        (previousPieceSelected !== currentPiece && (currentPiece.pieceType === PieceType.None || currentPiece.color !== previousPieceSelected.color)) 
      ) {
        MovePiece(store.gameBoard, previousPieceSelected, {row: cellRow, col: cellCol} as Position)
        store.updatePreviousPieceSelected(undefined);
        store.changePlayer();
      }
    };

但是,我在以下行中收到错误消息:

store.updatePreviousPieceSelected(currentPiece);

currentPiece(属于 Piece 类型)不可分配给 undefined 类型。我通过在我的商店中执行以下操作找到了使它起作用的技巧:

export const useStore = defineStore("game", {
  state: () => {
    return {
      moves: [],
      gameBoard:  getInitialBoard(),
      playerTurn: PieceColor.White,
      previousPieceSelected: getInitialPreviousPieceSelected()
    }
  },
  actions: {
    changePlayer() {
      this.playerTurn =
          this.playerTurn === PieceColor.White
            ? PieceColor.Black
            : PieceColor.White;
    },
    updatePreviousPieceSelected(piece: Piece | undefined ) {
      this.previousPieceSelected = piece
    }
  }
})

function getInitialPreviousPieceSelected(): Piece | undefined {
  return undefined;
}

但感觉很麻烦。在初始状态return中输入previousPieceSelected还有另一种方法吗?

this.previousPieceSelected的类型是从初始状态推断出来的,目前它被初始化为undefined,因此它具有undefined的类型(意味着它只能被分配undefined).

的值
  1. 在初始 undefined 值上使用 type assertion(即,as 关键字加上所需的 Piece | undefined 类型)。

  2. 另请注意,可以使用 ?: 而非 | undefined 指定可选参数。这只是一种更简单的写法。

export const useStore = defineStore("game", {
  state: () => {
    return {
      moves: [],
      previousPieceSelected: undefined as Piece | undefined, 1️⃣
    }
  },
  actions: {                          2️⃣
    updatePreviousPieceSelected(piece ?: Piece) {
      this.previousPieceSelected = piece
    }
  }
})

或者像这样

interface IUserState {
  user: null | IUser
}
    
export const useUserStore = defineStore({
  id: 'user',
  state: (): IUserState => ({
    user: null,
  })
...

getInitialBoard()来自哪里? 那是进口的吗? 您的初始化数据不应该是您的计算值。这更多是 pinia 中“getters”的功能。你有“状态”、“吸气剂”和“动作”。状态通常只是初始化的类型化变量。 getter 是在不改变状态数据的情况下计算出的可返回值。动作改变状态数据。您应该只使用存储操作更改状态数据,而不是从 pinia 外部的组件实例中更改状态数据。所有的数据,即真相的来源,一直都在 pinia 中。 以这种方式让您的商店井井有条:

// conceptual model e.g.
pinia {
  state: () => {
    return { data }
  },
  getters: { 
    // doesn't change data
    getter: (state) => state.data.returnComputedState(),
  },
  actions: { 
    // changes data
    action: () => this.data = mutateTheData(this.data),
  },
}

例如:

type UserState = {
  login: string
  isPremium: boolean
}


const useUserStore = defineStore<string, UserState>('user', {
  state: () => ({
    login: 'test',
    isPremium: false,
  }),
})

defineStore 是 TypeScript 中的通用函数,它接受两个参数,存储 ID 和状态。

/**
 * Creates a `useStore` function that retrieves the store instance
 *
 * @param id - id of the store (must be unique)
 * @param options - options to define the store
 */
export declare function defineStore<Id extends string, S extends StateTree = {}, G extends _GettersTree<S> = {}, A = {}>(id: Id, options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>): StoreDefinition<Id, S, G, A>;

因此可以定义 fully-typed State 和商店名称。

import { defineStore } from 'pinia';

interface State {
  borks: string[];
  isWoof: boolean;
}

interface Getters {}

interface Actions {
  addBork(bork: string) => void;
}

const useBorkStore = defineStore<'bork', State, Getters, Actions>('bork', {
  state: () => {
    return {
      borks: [],
      isWoof: false
    }
  },

  actions: {
    addBork(bork: string) {
      this.borks.push(bork);
    }
  }
})

export { useBorkStore };