在Vue3的reactive()对象上使用Partial似乎表现奇怪。

huangapple go评论72阅读模式
英文:

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

问题

我在使用 TypeScript 的 Partial 类型与 Vue3 的响应式对象时遇到了奇怪的行为。

我有一个简单的类型表示用户,并且需要创建一个可能一开始不具备某些属性的用户,因此我使用了 Partial 实用类型:

type User = {
  id: number
  name: string
}

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

// ✅ 这里一切都正常

显然,当我尝试在用户中添加其他内容时,它会抛出错误:

const user_1: Partial<User> = {
  name: 'John',
  alive: true
  // ❌ 类型 '{ … }' 不能分配给类型 'Partial<User>' [...] 'alive' 在类型 'Partial<User>' 中不存在
}

这是我从普通 TypeScript 中所期望的,所以这里没有问题。

但是奇怪的行为出现在我尝试使用部分对象声明一个 Vue3 响应式对象时:

import { reactive } from 'vue'

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

在这里,TypeScript 对于一切似乎都很清晰,不会产生任何问题。

奇怪的是,当我在模板中使用 user_2.alive 时,错误如预期地显示出来:

<template>
  <h1>{{ user_2.alive }}</h1>
  <!-- ❌ 属性 'alive' 在类型 'Partial<User>' 上不存在 -->
</template>

那么,为什么我在声明响应式对象时看不到错误呢?
我是否忽略了重要的内容,或者这可能是 TS 与 reactive() 的实现中的错误吗?

注意:我还尝试使用默认的 setup() 声明,以防它是与 <script setup> 注释有关的 bug,但问题仍然存在。

我也可以在 Vue3 Playground 接口上复现这个 bug:
[链接](https://play.vuejs.org/#eNp9UstOwzAQ/JWVLwUJpeJxCqESIIToASoeN19Muk1dHNuynVIU5d9ZO7QEqfTm3RnPzj5adm1ttm6Q5azwpZM2gBK6uuIseM7AY2jshGtZW+MCtOBQlEGuETpYOFPDiP6OLrnmOnxZhDePDq6g5RpAznPQTf2O7iSGWtSYgw9O6iolREVxT+C6ixKl0T6ANq4WKirlMBMuSKGKGE2GwhdnA9HR1Cz1qBdVZC6HhVAeSTU562W3zvcLb9GjfyrcoxNq/qdGcE0scUw1inE/O5oUBQFrq0RAigCK5emkbQdNZVERug6KMUEDytBglmoQ64dUjHei7IRWQy0tZJWtvNG0ueSZs9LUVip0TzZIapmzvJ9XxIRS5nOactF36iP9WWL5sSe/8puY42zmkPyskbMdFoSrMPTw3csjbui9A2szbxSxD4DP6I1qoseedtPoOdke8JLbh3RzdC2v/m4TUPttU/3gAbrE54xO8PZA6792z7Pz9I+2xrpvqPX/OQ==

英文:

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&lt;User&gt; = {
  name: &#39;John&#39;
}

// ✅ Everything&#39;s fine here

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

const user_1: Partial&lt;User&gt; = {
  name: &#39;John&#39;,
  alive: true
  // ❌ Type &#39;{ … }&#39; is not assignable to type &#39;Partial&lt;User&gt;&#39; […] &#39;alive&#39; does not exist in type &#39;Partial&lt;User&gt;&#39;
}

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 &#39;vue&#39;

const user_2: Partial&lt;User&gt; = reactive({
  id: 42,
  name: &#39;Gerald&#39;,
  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 :

&lt;template&gt;
  &lt;h1&gt;{{ user_2.alive }}&lt;/h1&gt;
  &lt;!-- ❌ Property &#39;alive&#39; does not exist on type &#39;Partial&lt;User&gt;&#39; --&gt;
&lt;/template&gt;

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 <script setup> 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==

答案1

得分: 1

你可以向 reactive 传递一个类型参数,以指定它接受的参数必须是那种类型:

const user_2 = reactive&lt;Partial&lt;User&gt;&gt;({
  id: 42,
  name: &#39;Gerald&#39;,
  alive: true, // 错误
});

否则,它将自动推断类型。由于赋值允许多余的属性(在这里,将函数调用的返回值赋给 user_2),所以这种赋值是允许的。

Playground

英文:

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

const user_2 = reactive&lt;Partial&lt;User&gt;&gt;({
  id: 42,
  name: &#39;Gerald&#39;,
  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

huangapple
  • 本文由 发表于 2023年6月29日 00:00:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76574903.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定