Differentiate the types of get and set specified in Vue reactivity properties

After the introduction of Variant Accessors in the latest version of TypeScript (TS 5.1), my interest peaked in creating composables like the one below:

export function useRouteQueryParam(param: MaybeRef<string>): WritableComputedRef<string | null>
export function useRouteQueryParam(param: MaybeRef<string>, defaultValue: string): WritableComputedRef<string>
export function useRouteQueryParam(param: MaybeRef<string>, defaultValue?: string): WritableComputedRef<string | null> {
  const paramRef = ref(param)
  const route = useRoute()
  const router = useRouter()

  return computed({
    get() {
      const [value] = asArray(route.query[paramRef.value])

      return value ?? defaultValue ?? null
    },
    set(value) {
      const query = { ...route.query, [paramRef.value]: value }
      router.push({ query })
    },
  })
}

In this scenario, it would be ideal to utilize variant accessors for the WritableComputedRef when a defaultValue is provided by the caller. The expectation is that the get function should always return a string, while still allowing the set function to accept either a string or null. However, due to the current syntax limitations of WritableComputedRef which only allows for a single type T, I am doubtful if this setup is feasible at the moment.

Answer №1

https://tsplay.dev/wea0af

import { computed, WritableComputedRef, DebuggerOptions, ComputedGetter, ComputedSetter } from 'vue'

declare class Accessor<G, S> {
    get value(): G;
    set value(value: G | S)
}
interface DualAccessRef<G, S> extends Omit<WritableComputedRef<G>, 'value'>, Accessor<G, S> { }
interface DualAccessOptions<G, S> {
    get: ComputedGetter<G>;
    set: ComputedSetter<G | S>;
}

export function dualAccessed<G, S = never>(
    options: DualAccessOptions<G, S>,
    debugOptions?: DebuggerOptions,
): DualAccessRef<G, Exclude<S, G>> {
    return computed(options, debugOptions);
}

;; let x = dualAccessed({
    // ^?
    // let x: DualAccessRef<number, string>
    get() { return 123 },
    set(v: number | string) { }
})

let b = x.value
//  ^?
// let a: number

x.value = 'bar';
// ok

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering a webpack mix issue on Ubuntu version 18

Whenever I try to execute the command ( npm run watch ), I encounter this error: @ development /home/nader/Desktop/asd/blog cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setu ...

Trouble encountered in nuxt/auth

When it comes to authentication, I utilize nuxt-auth. After a successful login, my intention is to redirect to the main page using this.$router.push('/'). However, upon doing so, I am encountering a blank page with the following message: 2021 ...

Can I create a focus event listener that will apply to all input elements within a Vue web application?

I currently have a web application built in Vue. I am looking to implement an event that triggers whenever an input/textarea field is focused. Is there a way to bind this event globally so that I don't need to manually add @focus="function" ...

Emphasizing main navigation item using router-link in VueJS

I have successfully implemented a split sidebar menu feature. The left side of the menu contains icons that, when clicked, activate a submenu on the right side. The submenu consists of router-link tags that allow me to apply the active class to the selecte ...

Using string interpolation and fetching a random value from an enum: a comprehensive guide

My task is to create random offers with different attributes, one of which is the status of the offer as an enum. The status can be “NEW”, “FOR_SALE”, “SOLD”, “PAID”, “DELIVERED”, “CLOSED”, “EXPIRED”, or “WITHDRAWN”. I need ...

Having trouble with Next.js 13 GitHub OAuth integration - it keeps redirecting me to Discord instead of signing me in

There's a perplexing issue troubling my application... The implementation of OAuth 2 with GitHub, Discord, and Google is causing some trouble. While Google and Discord authentication works smoothly, attempting to sign in via GitHub redirects me to Di ...

Tips for automatically closing the Toggle Navigation feature in Vue JS when a user clicks outside of the navigation container

Is there a way to close the toggled navigation menu automatically when the user clicks outside of the navigation container? I have implemented two ul menus inside the navigation menu and would like the subNavActive, safNavAcitve, and repNavUl variables to ...

Attempting to prevent redundant loading of a component repeatedly

Welcome to the Code Zone Incorporating Laravel 5.8 and Vue.js components for an enhanced user experience. Identifying the Problem Within the code structure, there exist 3 tabs. When Component 1 is selected, it loads successfully. Then when Component 2 i ...

Hey Vue with Eslint, can I ask you a question about data hosting?

Currently, I am working with Vue3 along with eslint and prettier. However, I am facing an issue with eslint errors. In my Vue project, the data URL for hosting images is as follows: image: 'https://picsum.photos/210/118/?image=1', but when I u ...

Is it possible to store any array of strings in localStorage?

I'm trying to save a list of addresses in local storage, like this: addresses["1 doe st, england","2 doe st, england", "3 doe st, england"] Each time I click on an address, I want it to be added to the array in local storage. However, my current imp ...

Top method for declaring and setting up variables in Angular 2

I've been diving into the Angular Style Guide, but a question has come up: what is the most effective method for initializing a variable in a component? For instance, should I declare a variable like so: export class MyComponent implements OnInit { ...

Is it possible to dynamically close the parent modal based on input from the child component?

As I follow a tutorial, I am working on importing the stripe function from two js files. The goal is to display my stripe payment in a modal. However, I am unsure how to close the modal once I receive a successful payment message in the child. Below are s ...

Sending nested JSON in Angular 2 Post Request

Are there any efficient ways to handle the task of importing raw JSON data and posting it to a server using an import function? For example, if a user copies and pastes the following JSON: { "name": "testing", "design": [ { "name": "test", ...

Only filter the array by its value if the value is specified

Is there a way to apply this filter while only checking each condition if the value is not undefined? For instance, if taxId is undefined, I would like to skip it rather than using it as a filter criterion. this.subAgencies = demoSubAgencies.filter(fun ...

What purpose does the question mark (?) serve after a class name when invoking class methods in TypeScript?

One interesting element within my TypeScript code snippet is the presence of the statement row?.delete();. I'm curious about the significance of the question mark in this context. What would be the outcome if 'row' happened to be null? Ap ...

Tips for dragging a column in ngx-datatable to scroll the horizontal scroll bar in Angular 4

Is there a way to make the horizontal scroll bar move when dragging the column header of ngx-datatable in Angular 4? I have a situation where the first column should trigger the movement of the horizontal scroll bar when dragged from left to right. Any s ...

Vue error: Uncaught promise rejection - RangeError: The computed value update has exceeded the maximum call stack size

My computed code snippet: computed: { display: { get() { return this.display }, set(newValue) { this.display = newValue } } }, Attempting to update the computed value from a function in ...

Understanding the True Meaning of v-model.number in Validating Input Using Vue.js

When using v-model.number to specify that my input field is numeric, what assumptions can I make when validating the numeric input before submitting the form or posting JSON to the server? Can I rely on it always being a number at this stage and focus on ...

Attempted to identify whether an item exists in an array, and if it does, then add the item to the array; if not, then perform

Allow me to make some clarifications as it might be a bit confusing initially. This project I'm working on is for school. I don't expect anyone to do it for me, but I need help with a specific part. I'm creating a simple shopping cart using ...

What is the process for importing a JSON file into the current Vue default configuration?

There is an incorrect answer that mentions tsconfig.json, which is no longer relevant in Vue projects. How can a JSON file be imported with VueJS / Typescript? I am assuming the configuration option { "compilerOptions": { "resolveJso ...