v-bind cannot be bound to a type wrapped by a Partial
Vue version
3.3.8
Link to minimal reproduction
Steps to reproduce
View error information
What is expected?
no error
What is actually happening?
Use Partial to define the type of props and cannot be passed to the v-bind directive.
System Info
System:
OS: Windows 10 10.0.19045
CPU: (12) x64 Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz
Memory: 3.43 GB / 15.87 GB
Binaries:
Node: 18.1.0 - E:\code\NodeJS\node.EXE
Yarn: 1.22.19 - E:\code\NodeJS\yarn.CMD
npm: 8.8.0 - E:\code\NodeJS\npm.CMD
pnpm: 8.10.5 - D:\yizhaotong-code\xueyuanjia-win\node_modules\.bin\pnpm.CMD
Browsers:
Edge: Spartan (44.19041.3636.0), Chromium (119.0.2151.72)
Internet Explorer: 11.0.19041.3636
npmPackages:
vue: ^3.3.8 => 3.3.8
Any additional comments?
No response
Try this:
<script setup lang="ts">
import { defineProps } from 'vue';
interface Conf {
foo: string;
}
const props = defineProps(['conf']);
</script>
<template>
<div v-bind="{ foo: conf.foo }" />
</template>
It looks like TypeScript is being a bit finicky when we try to directly bind a prop with a Partial
In TypeScript, when we use Partial
To make TypeScript happy and ensure a smooth binding process, we have a couple of options. One is to destructure the prop and bind its properties individually. In your case, it would look like this:
<template>
<div v-bind="{ foo: conf.foo }" />
</template>
This way, we explicitly state which properties we want to bind, and TypeScript is happy because it knows each property is there. This tells TypeScript that we are confident all properties are there, resolving any complaints. Hope this helps clarify why we're structuring the binding this way! If you have any more questions, feel free to ask.
@goktugerol-dev Thank you for your explanation.
But I'm right to write it this way. Essentially, the objects bound by v-bind are the same. But the results of type checking are different.
@RJQingHuan Both ways of writing the code achieve a similar outcome in terms of the actual behavior in the template. But, the difference is how TypeScript interprets and checks the types.
In v-bind="props.conf"
, TypeScript will check the type based on the type of props.conf. Since props.conf has the type Partial
In { foo: conf.foo }
, you are being explicit and directly specifying which properties you want to bind in the template. TypeScript is happy with this because it sees that conf.foo is explicitly provided.
The actual behavior in the template should be similar, but the level of type checking and the strictness of TypeScript's analysis can change between the two approaches. Choose the one that aligns with the level of type safety you want in your code. It's a good practice to be aware of how TypeScript infers types,
@goktugerol-dev Actually not right. Vue's defineComponent
function has the ability to unwrap refs, so in order to provide auto-unref ability inside <template>
, Volar accesses variables from defineComponent
. If you use props
, Volar will access to the variable directly, so this issue will not exist. I've provided a reproduction link (see above) which is a issue in core's type.
I debugged this and it seems to be caused by non strict null check, please update tsconfig.json
to at the very least have strictNullChecks
, that should prevent typescript from resolving the type to unknown
.
This PR https://github.com/vuejs/core/pull/9652 seems to fix this issue even with strictNullChecks:false
.
strictNullChecks:false
EDIT: I strongly recommend using strict=true
if you're using typescript, even though there's a PR that might fix it, because of the nature of this issue, we cannot maintain the fix, since we must run strictly
when doing typescript tests.
I'll close this issue since as explained, we can only recommend using typescript strictly.