takeaway

The author has more than 3 years of practical experience in React + TS, and deeply understands the role of TS in improving production efficiency. A new team has recently been installed, and the technology stack is Vue3 + TS, which is still a shelf and still some way from deep application. Therefore, the best practice of Vue3 + TS is the direction of the author’s recent research, and the periodical results are summarized and written for your reference.

Note: The demo scenario and some of the code in this article will be re-used from my other article on how Vue 3 and React 16.8 can be used, which will not cost too much extra reading.

background

When Vue 3.2 was released, UVU had already provided a best practice solution on Weibo:

<script setup> + TS + Volar = Delicious

Volar is a VS Code plugin that I personally think is most useful for solving the TEMPLATE TS prompt problem. Note that when using it, remove the Vetur first to avoid collisions.

< Script Setup > is a compile-time syntactic sugar for using composite apis in single-file components (SFC). It has many advantages over plain

  • Less boilerplate content, cleaner code.
  • You can declare props and emit events using pure Typescript.
  • Better runtime performance (their templates are compiled into renderers of the same scope as them, without any intermediate proxies).
  • Better IDE type inference performance (less work for the language server to extract types from code).

See the official documentation for single file components

In fact, the above content has basically solved most of the appeals, but there are still some needs that have not been met, mainly 2 points.

DefineProps does not currently support using TS types imported from other files.

Complex types and type imports from other files are not currently supported. In theory, it is possible to implement type imports in the future.

We need to provide a unified reference solution to guide the development of practice.

Second, no best practices for JSX patterns are given. While there are few scenarios where you have to use JSX to get the most out of TS once you have the basic scenario in place, the best is still possible. In order to make the topic more focused, this article will only briefly talk about the idea, the details will be another article.

In addition to the above two points, although THE DIRECTION of best practice is given by THE UNIVERSITY of Utah, some details, especially cases, are needed to guide the practice of the team. This paper will expand on the above three points respectively.

The target

First, clarify what best practices are intended to achieve:

  1. TS – friendly coding prompt and auto – complete in any scenario
  2. Component is passed in when usedChecksum prompt for props. Such as<input :value="value" />Component that verifies whether value is a string.
  3. TS flow layer by layer. For example, the template syntax of Vue should also be able to smoothly carry on the various functions of TS.

Best practices

Details added

Let’s use a form scenario as an example. To save space, check out Vue 3 and React 16.8 to see how much context can be found in the “Scenario Description” and “API & Types” sections. In addition, this section is representative enough to use only the Form example.

Demo – Form

<template>
  <div>
    <div>
      <div>Name</div>
      <input type="text" v-model="name" />
    </div>
    <div>
      <div>Sex</div>
      <input type="radio" name="sex" :checked="sex === Sex.male" @click="() => sex = Sex.male" />Male
      <input type="radio" name="sex" :checked="sex === Sex.female" @click="() => sex = Sex.female" />female</div>
    <p>
      <button @click="handleSubmit">Submit</button>
    </p>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import { Sex, fetchUserInfo, updateUserInfo } from ".. /services";
const name = ref("");
const sex = ref(Sex.male);

onMounted(() = > {
  fetchUserInfo("id-xxx").then((res) = > {
    name.value = res.name;
    sex.value = res.sex;
  });
});

const handleSubmit = () = > {
  const params = { name: name.value, sex: sex.value };
  updateUserInfo(params).then((res) = > {
    if (res) alert(JSON.stringify(params));
  });
};

</script>

Copy the code

The above implementation has several significant improvements over the normal Setup + Template implementation

  1. Lengthy return values are avoided and the amount of code is significantly reduced. In fact,

When using

So you don’t have to declare components anymore. This further reduces the code.

  1. By the way, import the TS enum type (Sex), which can also be easily used in the template.
  2. If Volar is installed, the template is also very friendly for Sex code prompting and verification.

As you can see, the development experience of < Script Setup > has improved significantly for common scenarios. Next is to supplement the other two mentioned above.

DefineProps cannot import TS externally

To simulate the props scenario, let’s change the Table example: instead of getting the userList from the API, the userList is passed in through the props.

Note: The logic to fetch data from the API is placed in the parent component TableWrapper, and the code is placed at the end of the text so as not to disturb the pace of the text.

<template>
  <table :cellPadding="5" :cellSpacing="5">
    <tr>
      <th>Name</th>
      <th>Sex</th>
    </tr>
    <tr v-if="userList.length === 0">
      No Data
    </tr>
    <tr v-else v-for="user in userList" :key="user.name">
      <td>{{ user.name }}</td>
      <td>{{ user.sex === Sex.male ? "Male" : "Female" }}</td>
    </tr>
  </table>
</template>
<script setup lang="ts">
import { defineProps, withDefaults } from "vue";
import { Sex, UserInfo } from ".. /services";

interface Props {
  userList: UserInfo[];
}
withDefaults(defineProps<Props>(), {
  userList: () = >[],});</script>

Copy the code

To start with the most important point, the official documentation that says “imports from other files are not supported” refers to the generic type received by defineProps, which is the Props above. But as you can see from the example, both Sex and UserInfo were imported from the outside and are actually usable. This means that in theory it only restricts cross-file reuse of type TS of Props at the component level. If that’s all it is, that’s acceptable. One is that there are generally few scenarios for reuse of Props between components. The other is that it can be solved by a more fine-grained declaration similar to the above example, but with some redundancy.

Here are a few more highlights:

  1. definePropsYou can use both runtime declarations and type declarations (see details)The official documentation), but not at the same time. In order to make TS flow better, it is recommended to use the above example in practiceType declarationWay.
  2. withDefaultsUsed to declare the default value of props, as defined by the runtime declarationdefaultIs in the same format.
  3. VolarThe template above can be given friendly TS hints and validations.

JSX best practice ideas

As mentioned above, with the above best practices, there are not many places where you need JSX. However, JSX has its own advantages (due to the long-standing React mentality), such as:

  1. More flexible, can use any JS syntax, see the official website case;
  2. Props does not need to convert small hump to “-“, which is more intuitive and does not add extra memory burden;

Of course, some will say it has its downsides, but let’s leave that aside and focus on the best practices of JSX. In fact, Functional Component is best implemented using JSX because it is simply a function. So how do ordinary components work? Please allow me to prepare for it first, and the address of another article will be attached later.

conclusion

So far, the basic framework of best practices for Vue3 + TS is in place, and it seems to be working pretty well. Depending on the team’s actual situation, add some practical details of the specification, can be happy to practice in the project.

One thing the author is quite certain about is that TS will be used more and more in front-end projects, because it is very obvious to improve the development efficiency and quality. So using TS in a project is cost-effective for both the team and the individual. Of course, we also need to take the migration cost into account. If we want to use TS, we need to upgrade to Vue3. If you force THE Vue2 to use TS, trust me, you won’t like it.

Finally, it’s said that “I don’t want to use JavaScript anymore after WORKING with TypeScript.” I bought it anyway.

reference

  • Talk about Vue templates and JSX
  • Vue3 official document (strongly recommended to read carefully, such a good document is rare)

Code the appendix

TableWrapper.vue

<template>
  <Table :user-list="userList" />
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import { fetchUserList, UserInfo } from ".. /services";
import Table from "./Table.vue";
const userList = ref<UserInfo[]>([]);

onMounted(() = > {
  fetchUserList().then((res) = > {
    userList.value = res;
  });
});
</script>
Copy the code