Reputation: 2093
I have a Pinia + TypeScript store named user.ts
that looks like this:
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
},
},
});
The state is a FireBase User object.
And I want to update photoURL
using the setPhotoURL()
action.
But photoURL
has this TypeScript error:
Cannot assign to 'photoURL' because it is a read-only property. ts(2540)
What am I doing wrong?
Is this the correct way to update state?
Upvotes: 2
Views: 4608
Reputation: 138526
You can remove the readonly
modifier by mapping the type :
Mapping Modifiers
There are two additional modifiers which can be applied during mapping:
readonly
and?
which affect mutability and optionality respectively.You can remove or add these modifiers by prefixing with
-
or+
. If you don’t add a prefix, then+
is assumed.// Removes 'readonly' attributes from a type's properties type CreateMutable<Type> = { -readonly [Property in keyof Type]: Type[Property]; };
If the type has nested properties that you want to be writeable, map recursively:
type CreateMutable<T> = { -readonly [P in keyof T]: CreateMutable<T[P]> }
Then use it to type the store's user
property:
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
},
},
})
Upvotes: 1
Reputation: 90188
'firebase/auth'
declares User interface as having readonly
props. When you forcefully apply that interface to your state object, TS trusts you.
Spreading it should remove the readonly
from its props, while still inferring the types:
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: {
//...
}
})
Upvotes: 1