vue.js - Kun käytät Piniaa ja TypeScriptiä, miten käytät Actionia tilan (State) asettamiseen?


Minulla on Pinia + TypeScript -store nimeltä user.ts, joka näyttää tältä:

import { User } from 'firebase/auth';
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
  state: () =>
    ({
      displayName: null,
      email: null,
      emailVerified: null,
      isAnonymous: null,
      metadata: null,
      multiFactor: null,
      phoneNumber: null,
      photoURL: null,
      providerData: null,
      providerId: null,
      refreshToken: null,
      tenantId: null,
      uid: null,
    } as unknown as User),
  actions: {
    setPhotoURL(photoURLData: string | null) {
      this.photoURL = photoURLData; //<-- ERROR HERE
    },
  },
});

Tila on FireBase-käyttäjäobjekti.

Ja haluan päivittää photoURL-kentän käyttämällä setPhotoURL()-toimintoa.

Mutta photoURL aiheuttaa tämän TypeScript-virheen:

Cannot assign to 'photoURL' because it is a read-only property. ts(2540)

Mitä teen väärin?

Onko tämä oikea tapa päivittää tila?

Vastaus #1

Voit poistaa readonly-määreen määrittämällä tyypin uudelleen seuraavasti:

Muokkainten kartoittaminen

On olemassa kaksi lisämääritettä, joita voidaan soveltaa kartoituksen aikana: readonly ja ?, jotka vaikuttavat muokattavuuteen ja valinnaisuuteen vastaavasti.

Voit poistaa tai lisätä näitä modifikaattoreita lisäämällä etuliitteen - tai +. Jos et lisää etuliitettä, oletetaan +.

// Removes 'readonly' attributes from a type's properties
type CreateMutable<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};

Jos tyypillä on sisäkkäisiä ominaisuuksia, jotka haluat olevan kirjoitettavissa, tee kartoitus rekursiivisesti:

type CreateMutable<T> = { -readonly [P in keyof T]: CreateMutable<T[P]> }

Sitten käytä sitä kirjoittaaksesi kaupan user-ominaisuuden:

import type { User } from 'firebase/auth'
import { defineStore } from 'pinia'

type CreateMutable<T> = { -readonly [P in keyof T]: CreateMutable<T[P]> }

export const useUserStore = defineStore('user', {
  state: () => ({ user: {} as CreateMutable<User> }),

  actions: {
    setPhotoURL(photoURLData: string | null) {
      this.user.photoURL = photoURLData
    },
  },
})

Vastaus #2

'firebase/auth' määrittelee User-rajapinnan omaavan readonly-ominaisuudet. Kun pakotat kyseisen rajapinnan tilamuuttujaasi, TS luottaa sinuun.

Levittäminen pitäisi poistaa readonly sen ominaisuuksista, samalla kun tyypit johdetaan:

export const useUserStore = defineStore('user', {
  state: () => ({ ...({
    displayName: null,
    email: null,
    emailVerified: null,
    isAnonymous: null,
    metadata: null,
    multiFactor: null,
    phoneNumber: null,
    photoURL: null,
    providerData: null,
    providerId: null,
    refreshToken: null,
    tenantId: null,
    uid: null,
  } as unknown as User) }),
  actions: {
    //...
  }
})