DEV Community

Cover image for How to provide types for route query parameters in Vue3
Uncle Pushui
Uncle Pushui

Posted on

How to provide types for route query parameters in Vue3

Preface

Recently, a Vue3 framework that supports IOC containers was released: Zova. Unlike previous OOP or Class solutions, Zova still uses Setup syntax at the ui interaction side and only introduces IOC containers at the business side. IOC containers are like a key that opens the door to business engineering for us, allowing us to explore more engineering designs and capabilities. A netizen made a very good suggestion: Can you provide some business scenarios to explain what Class can do but Composable can't do, so that it will be more convincing.

First of all, it should be noted that there are actually no business requirements that can be done by this and not by that. Different programming paradigms bring different code styles and different programming experiences, pointing to the evaluation of development efficiency and code maintainability from different paths. Therefore, it ultimately depends on the user's own habits and actual business requirements.

So, here, we will take this topic How to provide types for route query parameters in Vue3 as an example to see what the code styles of Composable and IOC containers are different.

Business requirements

Here is a page component User, which can pass three parameters through Query:

Param Type Default
id number 0
name string ''
married boolean false

Composable: native

1. Open page

const router = useRouter();
router.push({
  path: '/test/demo/user',
  query: {
    id: 1,
    name: 'kevin',
    married: false.toString(),
  },
});
Enter fullscreen mode Exit fullscreen mode

From the perspective of Typescript types, this code has the following two problems:

  1. path: no type constraints and autocompletion. This will have the following three hidden dangers:
    1. Can't remember: If the path is long or the words are complex, you can't remember the path and need to find it from the source file
    2. Written wrong: If you accidentally write it wrong, there is no prompt, and the error will only be exposed when it is actually run
    3. Changed: If the path is changed during subsequent code maintenance, there will be no prompt in the code here, and the error will only be exposed when it is actually run
  2. query: only limited type constraints, inconsistent with business types
    1. For example, Boolean type is not supported and must be forced to String type

2. Obtain parameters

const route = useRoute();
const id = parseInt(route.query.id ?? 0);
const name = route.query.name ?? '';
const married = route.query.married === 'true' ? true : false;
Enter fullscreen mode Exit fullscreen mode

Since no type tool is provided, each parameter needs to be processed separately

Composable:useRouteQuery

1. Open page

(Same as above)

2. Obtain parameters

import { useRouteQuery } from '@vueuse/router';

const id = useRouteQuery('id', 0, { transform: Number });
const name = useRouteQuery('name', '');
const married = useRouteQuery('married', 'false', {
  transform: value => {
    return value === 'true' ? true : false;
  },
});
Enter fullscreen mode Exit fullscreen mode

IOC container

1. Define types

import { zz } from 'zova';

export const QuerySchema = zz.object({
+  id: zz.number().default(0),
+  name: zz.string().default(''),
+  married: zz.boolean().default(false),
});
Enter fullscreen mode Exit fullscreen mode
  • zz is an enhanced version based on zod, which is specially processed for route parameters and supports array and json. For details, see: Zova: zod
  • You can specify the default value when defining the types

Image description

2. Open page

const url = this.$router.resolvePath('/test/demo/user', {
  id: 0,
  name: 'kevin',
  married: false,
});
this.$router.push(url);
Enter fullscreen mode Exit fullscreen mode
  • The parameters of resolvePath have type constraints and autocompletion, and are consistent with the business types

Image description

3. Obtain parameters

const id = this.$query.id;
const name = this.$query.name;
const married = this.$query.married;
Enter fullscreen mode Exit fullscreen mode
  • Get parameter values ​​directly through this.$query, with precise types and no need to handle default values

Image description

Conclusion

From the above example comparison, we can see that the IOC container can separate the definition from the usage, and the scaffolding can be created by tools on the definition side to further simplify the writing of the definition. Since the normative codes such as TS types and default values ​​are completed on the definition side, the code on the usage side is more concise and intuitive. I don't know what your code style is, and if there is a better way to implement it, you are welcome to communicate in the comment area.

References

Top comments (0)