-
Notifications
You must be signed in to change notification settings - Fork 342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expanding ComputedGetter's return type #738
Comments
Hi, I tried to read the official Vue3 documentation and the implementation of computed in the reactivity system, and found that from Vue2's type declaration to the present, the types of computed The definition is always like this. Perhaps we should consider the usage scenarios of the code. Usually we don’t write More often we will implement the So from the perspective of usage scenarios, the official type declaration does not seem to have an impact on usage. Perhaps you can set it up to elaborate on your usage scenarios. |
Hello, Thank you for your informative reply. I had not considered that the issue would come from Vue's core reactivity system itself, so I apologize if this is not the right place to discuss this request. The reverse case you bring up (getter of type const computedValue = computed({
get: (): string => {
return someValue;
},
set: (newValue: string | null): void => {
someValue = newValue || "";
}
}; For my use case specifically, I am storing a For example, one of the preferences might be "Profile visibility": As the user selects a new value for the preference, the value in the store is updated (and a server call is made to save the new preference). This preferences page may not realistically be accessible in the case where the The relevant code (unnecessary cruft removed) is as follows: const store = getStore();
const user = computed<User | null>(() => store.getters["auth/user"]); // null if the user is not logged in, and User type if logged in
// v-model on a dropdown element
const profileVisibilitySelection = computed({
get(): ProfileVisibilityEnum | null {
return user.value?.meta.privacySettings?.profileVisibility || null;
},
async set(newValue: ProfileVisibilityEnum): Promise<void> {
// store old value in case it's needed later
const oldValue = user.value?.meta.privacySettings?.profileVisibility || null;
// immediately update local data for user experience, rollback later if necessary
store.commit(
"auth/setUser",
Object.assign({}, user.value, {
meta: {
...user.value?.meta,
privacySettings: {
...user.value?.meta.profileVisibility,
profileVisibility: newValue,
},
},
})
);
// send updated value to server to be confirmed
const serverResponse =
await axios.request({
method: "patch",
url: "/api/auth/me/preferences",
data: {
profileVisibility: newValue,
},
});
// rollback the change if server rejected request
if (!serverResponse.status !== 200) {
store.commit(
"auth/setUser",
Object.assign({}, user.value, {
meta: {
...user.value?.meta,
privacySettings: {
...user.value?.meta.profileVisibility,
profileVisibility: oldValue,
},
},
})
);
}
},
}); There are currently some workarounds in consideration for my case:
async set(newValue: ProfileVisibilityEnum | null): Promise<void> {
...
}
const profileVisibilitySelection = ref<ProfileVisibilityEnum | null>(user.value?.meta.privacySettings?.profileVisibility || null);
watch(
profileVisibilitySelection,
() => {
// update store and perform asynchronous operation here
}
);
get(): ProfileVisibilityEnum {
return user.value?.meta.privacySettings?.profileVisibility || ProfileVisibilityEnum.private;
},
get(): ProfileVisibilityEnum {
return user.value?.meta.privacySettings?.profileVisibility as ProfileVisibilityEnum;
}, |
Hello, Sorry for taking so long to reply to you. After reading your case and your own thinking about the solution, I think case one is the main way to solve your problem. Let’s talk about type definition first (this is our main issue). In the description of In your business code, my understanding is that you will immediately respond to the user's actions (although there will be some side effects after the value is changed in a certain place), and then use the results returned to you in the background to determine whether you need to respond to the user's Operation (otherwise the value is rolled back to before the corresponding). From the perspective of user operations, I may receive up to three status changes.
If the value is changed from the user, that is, when the So in this issue, I think the definition of the |
Hello, Thank you for your reply and valuable insight. Please do not worry about your English. It was perfectly understandable. Your wonderful analogy of the You are correct that it was my intention to immediately respond to the user's actions. It was my design intention such that every change on the user's side could be done atomically without the need for a "Save changes" button. I had set up an indicator component to inform the user that the asynchronous call is in progress and a success/fail component at its conclusion. After thinking over your comments, it is clear that I had made an oversight in the case of poor internet connection. As you describe, the user experience will be severely degraded as the server calls may take a long time or fail altogether. From this possibility, I think it is clear to me now that my approach to this specific problem needs to be reconsidered. Please consider my specific business case to be resolved now. As for the more general use cases for the expansion or separation of types between the Thank you for your time to discuss this issue together. It is very much appreciated. |
I am attempting to use a computed value in the
setup()
block of a component, such as follows:The getter normally returns a string, but as it also can sometimes be null. I therefore annotated the getter's return as
string | null
. (The value in the store is initialized elsewhere, hence the possibility of the null value.)However, I'm getting a Vetur error 2769 on the
get()
due to the return value ofnull
not being assignable tostring
.I believe this error occurs due code in the following files:
In this code, the type that is used for the argument for ComputedSetter is reused as the return type of the ComputedGetter. So in this case, the TypeScript error occurs because it is attempting to coerce the return type of the
get
function tostring
instead ofstring | null
.Might it be possible to allow the getter function's return type to be a superset containing the type passed into the setter?
The text was updated successfully, but these errors were encountered: