-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
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
TypeScript's defineProps
macro does not properly map to the object version in the case of booleans
#8576
Comments
FYI, the return type of interface Props {
foo?: boolean
}
const p = defineProps<Props>()
// ^ { foo: boolean }
p.foo
// ^ boolean The interface declares The default casting behavior is indeed something that we cannot easily change due to potential breakage, but I don't think your case should be considered an error either. When using an explicit |
This statement didn't make sense to me:
I'm not sure what you mean "correctly excludes". It's not correct according to TypeScript and the runtime does support |
@yyx990803 Here's an even worse, more egregious example, where Vue's type inference is way off-base. I made a component with these props (I've reduced it to the specific problem): interface Props {
error?: string | true
}
defineProps<Props>() Now, in this case, the The safest thing to infer as a default value? Obviously, it's In fact, if I write this: if (props.error === false) {} ...I get the error TypeScript itself is stating (correctly) that Vue is not handling types correctly, is abusing the type system, and is assigning values which violate those types and which could lead to runtime errors. This is a bug. Please re-open. |
At the very least, can there be changes to the Vite / Webpack plugins to fix this behavior for the Something like: vue({
script: {
accurateTypes: true
}
}) |
I've found workaround is to use uppercase/class version of |
I've created useForwardProps as another workaround for this issue as it is quite crucial for radix-vue. I've also pointed out some pain point and challenges here vuejs/vue#4792 (comment) |
@SnosMe Your comment is great! I think that's actually a '@typescript-eslint/ban-types': [
'error',
{
types: {
Boolean: false
},
extendDefaults: true
}
]
interface Props {
error?: string | true
}
defineProps<Props>() As I note in that comment, there are only 3 possible values based on that type: So, with a type like that, you're kind of outta luck unless you use withDefaults I guess? 🤔 |
请问怎么去解析这种情况: type Props = {
prop?: true | string
} 明确都排除了不能传 false 还是默认转换为false 吗?这个 defineProps 明显就是一个 bug ,为什么要担心破坏性更改。 官方明确说明了只有是 boolean 类型才会默认转换。 type Props = {
dom?: VNodeChildAtom
} 只是因为 VNodeChildAtom 中含有 boolean 类型就给我转换为 false。我无法相信怎么会有这么反直觉的行为 这个 bug 提出这么久了,为什么还没解决了。如果是 bug 为什么要担心所谓破坏性更改了 |
This issue can lead to application corruption after updating dependencies. |
The issue is that there is a wrong assumption at the bottom. Yes, booleans should be true or false BUT assuming you want booleans here is not correct. What is needed in the context of templates, etc. are optional booleans. This case has been made several times and with good examples as to why this is true. It's somewhat understandable how we got here but not why we have to stick with this. |
100% and I'm so glad you said this. What you're defining with your TypeScript is not a What prop: {
type: [Boolean, undefined],
default: undefined
} So, Vue's maintainers have made a lot of hullabaloo about this and related TS issues, saying this aligns with Vue's handling of booleans. But it doesn't because this doesn't define a boolean in TypeScript. So it has absolutely nothing to do with Vue's default value for a type of boolean, because these are not booleans. TypeScript's |
什么时候能把这个问题解决下,拖了很久了,这是一个严重的 bug 。特别是在基于组件二次封装时,会出现不可预料的问题,烦请看一下大家对于该问题的理解。mdn 明确说明,只有类型为 boolean 时默认才为 false ,你这里是只要包含 boolean 类型就默认为 false。并未达到对齐 mdn attrs 规范的目的。它是个 bug 就应该解决,而不是担心其破坏性更改 |
What problem does this feature solve?
Vue has an unexpected behavior where if you do this:
...the value of
foo
, if not specified, will befalse
instead ofundefined
. This is somewhat unexpected, as noted in vuejs/vue#7646 and vuejs/vue#4792, but my guess is that this was a conscious choice by Vue to imitate the behavior certain HTML values, at least their values in the DOM.The problem comes in the TypeScript extension of Vue. Say you have this:
TypeScript is very clear about interface syntax, which is that
foo?: boolean
means that the value offoo
will beundefined
if it is not specified. The type, in fact, is notboolean
butboolean | undefined
from TypeScript's perspective.Meaning, the most accurate translation of TypeScript to Vue's JavaScript API when passing an interface would be:
I would consider this a bug of not interpreting a TypeScript interface accurately, BUT it could be also considered a feature request as supporting optional properties in TypeScript, which may have not been fully implemented.
What does the proposed API look like?
Ideally, the API would be identical:
However, it's rational that there would be concern about breaking changes, so this is what I propose, which is a compile-time error vs a possible runtime change:
withDefaults(defaultProps<Props>, {})
, anyboolean
type should be required in thewithDefaults
object, so that the developer can make it clear if they are intending the default Vue behavior, or the default TypeScript behavior.withDefaults
macro would be required with adefaultProps
macro if, again, there are boolean types in the interface, but that could be considered too high of a burden for developers.So, my proposal, at minimum, is that the provided script block throws an error (or I can set a TypeScript strictness check to throw an error?). Thanks for considering this.
The text was updated successfully, but these errors were encountered: