Javascript is required
·
3 min read

What's New in Vue 3.3

What's New in Vue 3.3 Image

Vue 3.3 "Rurouni Kenshin" is now available and "is focused on developer experience improvements".

In this article, I give an overview of the highlighted features in Vue 3.3. Read the changelog if you are interested in all changes of this new version.

Props Destructuring

Warning

This feature is experimental and requires explicit opt-in.

I think this is one of the coolest features of the new release. You can now destructure props without losing reactivity and also set default values:

1<script setup lang="ts">
2const { counter = 0, testId = 'counter' } = defineProps<{ counter?: number; testId?: string }>()
3</script>

In my opinion, this is a very clean and "natural" way to define your props. Previously you had to use toRefs in combination with withDefaults to achieve the same result:

1<script setup lang="ts">
2const { counter, testId } = toRefs(
3  withDefaults(defineProps<{ counter?: number; testId?: string }>(), { counter: 0, testId: 'counter' })
4)
5</script>

defineModel

Warning

This feature is experimental and requires explicit opt-in.

Vue 3.3 provides a very elegant way to support two-way binding with v-model. Before 3.3 you had to write a lot of boilerplate code to support it:

1<script setup>
2const props = defineProps(['modelValue'])
3const emit = defineEmits(['update:modelValue'])
4
5function onInput(event) {
6  emit('update:modelValue', event.target.value)
7}
8</script>
9
10<template>
11  <input :value="modelValue" @input="onInput" />
12</template>

With 3.3 we can achieve the same functionality with less code:

1<script setup>
2const modelValue = defineModel()
3</script>
4
5<template>
6  <input v-model="modelValue" />
7</template>

In this example, the defineModel macro automatically registers a prop modelValue and returns a ref that can be directly mutated. Additionally. it registers the update:modelValue event.

Improved TypeScript Type Support

In the past, only local types such as type literals and interfaces could be used in the type parameter position of the defineProps and defineEmits compiler macros.

The reason for this was that Vue needed to analyze the properties on the props interface to create runtime options. However, this limitation has been addressed in version 3.3. The Vue compiler can now handle imported types and a limited set of complex types:

1<script setup lang="ts">
2import type { Props } from './foo'
3
4// imported + intersection type
5defineProps<Props & { extraProp?: string }>()
6</script>

Generic Components

Your components can now accept generic type parameters via the generic attribute if you are using <script setup>:

1<script setup lang="ts" generic="T">
2defineProps<{
3  items: T[]
4  selected: T
5}>()
6</script>

More Ergonomic defineEmits

Typing defineEmits was a bit verbose before 3.3:

1<script setup lang="ts">
2const emit = defineEmits<{
3  (e: 'foo', id: number): void
4  (e: 'bar', name: string, ...rest: any[]): void
5}>()
6</script>

Vue 3.3 provides a "more ergonomic" way:

1<script setup lang="ts">
2const emit = defineEmits<{
3  foo: [id: number]
4  bar: [name: string, ...rest: any[]]
5}>()
6</script>

Use console in the template

You can now use console in your template:

1<script setup>
2import { ref } from 'vue'
3
4const count = ref(0)
5</script>
6
7<template>
8  <h1>{{ count }}</h1>
9  <button @click="console.log(++count)">Increment</button>
10</template>

In previous versions of Vue, this caused an error: TypeError: Cannot read properties of undefined (reading 'log')

Try it yourself

Conclusion

Vue got so much better with this new version. The new features improve the developer experience and I'm very excited to see how the framework further evolves with the next upcoming releases.

For more information, read the official announcement and the GitHub changelog.

If you liked this article, follow me on Twitter to get notified about new blog posts and more content from me.

Alternatively (or additionally), you can subscribe to my weekly Vue newsletter:

I will never share any of your personal data. You can unsubscribe at any time.

If you found this article helpful.You will love these ones as well.
Unlocking the Power of v-for Loops in Vue With These Useful Tips Image

Unlocking the Power of v-for Loops in Vue With These Useful Tips

Focus & Code Diff in Nuxt Content Code Blocks Image

Focus & Code Diff in Nuxt Content Code Blocks

Lazy Load Vue Component When It Becomes Visible Image

Lazy Load Vue Component When It Becomes Visible

A Comprehensive Guide to Data Fetching in Nuxt 3 Image

A Comprehensive Guide to Data Fetching in Nuxt 3