Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Using Partial<Type> on a Vue3 reactive() object is acting strangely

I’m facing a weird behavior when using a TypeScript Partial type with a Vue3 reactive object.

I have a simple type representing a User, and need to create a user that may not have some properties at first, so I used a Partial utility type :

type User = {
  id: number
  name: string
}

const user_1: Partial<User> = {
  name: 'John'
}

// âś… Everything's fine here

Obviously when I try to put something else in that user, it throws an error :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const user_1: Partial<User> = {
  name: 'John',
  alive: true
  // ❌ Type '{ … }' is not assignable to type 'Partial<User>' […] 'alive' does not exist in type 'Partial<User>'
}

This is what I expect from plain TypeScript so no problem here.

But the strange behavior occurs when I try to declare a Vue3 reactive object with that partial :

import { reactive } from 'vue'

const user_2: Partial<User> = reactive({
  id: 42,
  name: 'Gerald',
  alive: true
})

Here everything seems to be clear for TypeScript which doesn’t yield anything.

What’s strange is when I use that user_2.alive in the template, the error shows up as expected :

<template>
  <h1>{{ user_2.alive }}</h1>
  <!-- ❌ Property 'alive' does not exist on type 'Partial<User>' -->
</template>

So, why can’t I see the error at the declaration of the reactive object ?
Did I omit something important or could that be a bug in the implementation of TS with reactive()?

Note: I also tried using the default setup() declaration, in cas of it would be a bug with the annotation, but the problem still remains

I could also reproduce the bug on the Vue3 Playground interface here :
https://play.vuejs.org/#eNp9UstOwzAQ/JWVLwUJpeJxCqESIIToASoeN19Muk1dHNuynVIU5d9ZO7QEqfTm3RnPzj5adm1ttm6Q5azwpZM2gBK6uuIseM7AY2jshGtZW+MCtOBQlEGuETpYOFPDiP6OLrnmOnxZhDePDq6g5RpAznPQTf2O7iSGWtSYgw9O6iolREVxT+C6ixKl0T6ANq4WKirlMBMuSKGKGE2GwhdnA9HR1Cz1qBdVZC6HhVAeSTU562W3zvcLb9GjfyrcoxNq/qdGcE0scUw1inE/O5oUBQFrq0RAigCK5emkbQdNZVERug6KMUEDytBglmoQ64dUjHei7IRWQy0tZJWtvNG0ueSZs9LUVip0TzZIapmzvJ9XxIRS5nOactF36iP9WWL5sSe/8puY42zmkPyskbMdFoSrMPTw3csjbui9A2szbxSxD4DP6I1qoseedtPoOdke8JLbh3RzdC2v/m4TUPttU/3gAbrE54xO8PZA6792z7Pz9I+2xrpvqPX/OQ==

>Solution :

You can pass a type parameter to reactive to say that the argument it takes must be of that type:

const user_2 = reactive<Partial<User>>({
  id: 42,
  name: 'Gerald',
  alive: true, // ERROR
});

Otherwise, it will be inferred automatically. Since excess properties are allowed in assignment (here, assigning returned value from function call to user_2), the assignment is allowed.

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading