Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v-bind cannot be bound to a type wrapped by a Partial #9639

Closed
RJQingHuan opened this issue Nov 20, 2023 · 6 comments · May be fixed by #9652
Closed

v-bind cannot be bound to a type wrapped by a Partial #9639

RJQingHuan opened this issue Nov 20, 2023 · 6 comments · May be fixed by #9652
Labels
has workaround A workaround has been found to avoid the problem scope: types

Comments

@RJQingHuan
Copy link

Vue version

3.3.8

Link to minimal reproduction

https://play.vuejs.org/#eNp9kjFPwzAQhf/KyUuLVNqhWxQqQdUBBqigo5eQXIKLc7ZsJ1Sq8t85O7QUCXWJcve+l7yX+CjurZ33HYpM5L50ygbwGDoLuqDmTorgpVhJqrBWhC82KEN+egQqWsxgskMfJjDcSDohW2esz9N1NU17RQFdXZQIa0M1HCUB1MZk4INT1Ega/lLJO2IlGzLYFi6oQufRzlEYzxdjVJ54CNhaXQTkCSCvVA/97buiitPHB0gBC5byxQUnZlwsiqqZ770hbp9eGB2tVRrdT1UpsjFK1AqtzddT2gXX4ey0Lz+w/Pxnv/eHuJNi69Cj61GKsxYK12AY5c3bMx74/iy2puo001fEV/RGdzHjiD10VHHsCy6lfWyt4a9Hzc5vDgHJn0rFoJEcEi8FH4H1leq/cZfzZfLxjxDDN/ubwb0=

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.

image

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

@RJQingHuan RJQingHuan changed the title The props after the v-bind binding is packaged by the Partial reports an error. v-bind cannot be bound to a type wrapped by a Partial Nov 20, 2023
@goktugerol-dev
Copy link

goktugerol-dev commented Nov 23, 2023

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 type using the v-bind directive in Vue. Let me break it down for you.

In TypeScript, when we use Partial, we're essentially saying that all properties of T are optional. Now, when we attempt to bind such a partially defined prop using v-bind, it gets a bit confused. Vue's v-bind expects all properties to be present because it dynamically binds them.

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.

@RJQingHuan
Copy link
Author

@goktugerol-dev Thank you for your explanation.

1700794048355

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.

@goktugerol-dev
Copy link

@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, TypeScript will understand that some properties might be missing, and it expects them to be optional. It's less explicit about which properties are being bound, so TypeScript's type checking is a bit more lenient.

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,

@so1ve
Copy link
Member

so1ve commented Nov 24, 2023

@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.

@pikax
Copy link
Member

pikax commented Nov 30, 2023

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 #9652 seems to fix this issue even with strictNullChecks:false.

image

strictNullChecks:false
image

typescript playgroun
image


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.

@pikax pikax closed this as completed Nov 30, 2023
@pikax pikax added the has workaround A workaround has been found to avoid the problem label Nov 30, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Dec 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has workaround A workaround has been found to avoid the problem scope: types
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants