-
-
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
Problem typing optional props with exactOptionalPropertyTypes enabled in tsconfig #6532
Comments
For now, just use const props = defineProps<{
modelValue?: number
}>(); |
That's what I originally tried, but I also have
If I add const props = defineProps<{
modelValue?: number | undefined
}>();
This could be a |
When and where exactly is that error being raised? Do you also get an error in VSCode/your IDE? As an experiment, try this please: const props = defineProps<{
modelValue?: number | undefined
'onUpdate:modelValue'?: undefined | (value: number | undefined) => any
}> and don't use I'd suspect that vue(-tsc) has a problem with the event prop generated from the defineEmits rather than the modelValue prop, as that one is missing the |
I get the errors both in VS Code with Volar when the file is open and when running I tried your changes, I still get type errors. Volar:
|
Okay, so I can kinda reproduce this, but a full repro from your side in a github repo would be apprechiated to make sure we are looking at the same things. I have:
This is HelloWorld.vue ...: const props = defineProps<{
msg?: string | undefined;
}>(); This is what I have in the parent's state: import { ref, Ref } from 'vue'
const nameRef: Ref<string | undefined> = ref("Tom");
let name: string | undefined = "Tom"; Both, when used for I think it is because the type generated for the props object that will be passed to the child is: {
msg: string | undefined
} while the type from the child component is: {
msg?: string | undefined
} So we could get rid of the question mark, but then we can't leave the prop completely absent in the parent. Not sure if this needs to be solved in Vue core, our JSX types or vue-tsc? /cc @pikax @johnsoncodehk What do you think? |
In plain TypeScript there is no problem with leaving the question mark in, so it is related to Vue & co somehow. There are no reported errors in the code below with // test.ts
interface Props {
required: string
optional?: string | undefined
}
const p1: Props = { required: "req", optional: "opt" }
const p2: Props = { required: "req", optional: undefined }
const p3: Props = { required: "req" }
let optional: string | undefined = "opt"
const p4: Props = { required: "req", optional }
export { p1, p2, p3, p4 } |
That's because in your example you are essentially casting all 4 objects to be of type I think what happens in this issue is more like this (pseudocode, and a bit backwards): interface PropsExtractedFromParentTemplate {
msg?: string | undefined
}
interface PropsFromChildComponentDef {
msg: string | undefined
}
const propsFromParent: PropsExtractedFromParentTemplate = {
msg: 'Tom'
}
propsFromParent.msg
function ChildComponent(props: PropsFromChildComponentDef) {
props.msg
}
ChildComponent(propsFromParent) // will error |
I would say having I think this problem is related with the generation of the code when using |
@pikax So there's two layers to this:
Would you agree? |
For Volar/vue-tsc, please track vuejs/language-tools#1798. |
There are one more problem: Type definitions of native elements. For example, this simple component from Nuxt Content has type error with This problem can't be resolved without modifying native types in ref: #6068 For your reference, in the type definition of react, all optional props has |
The linked PR (#6533) does solve the issue for me. Maybe it can be looked at and merged in? |
Any progress on this issue? |
Bump - I also have this issue Here's what works for me now <script setup lang="ts">
import {ButtonHTMLAttributes} from 'vue';
defineProps<ButtonHTMLAttributes>();
</script> <template>
<button :type="type ?? 'button'">
<slot />
</button>
</template> Here's what I expect to work <script setup lang="ts">
import {ButtonHTMLAttributes} from 'vue';
withDefaults(defineProps<ButtonHTMLAttributes>(), {type: 'button'});
</script> <template>
<button :type="type" >
<slot />
</button>
</template> Error caused error TS2379: Argument of type '{ type: "button" | "reset" | "submit" | undefined; class: string; }' is not assignable to parameter of type 'ButtonHTMLAttributes & ReservedProps & Record<string, unknown>' with 'exactOptionalPropertyTypes: true'.
Consider adding 'undefined' to the types of the target's properties. Type '{ type: "button" | "reset" | "submit" | undefined; class: string; }' is not assignable to type 'ButtonHTMLAttributes' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'type' are incompatible.
Type '"button" | "reset" | "submit" | undefined' is not assignable to type '"button" | "reset" | "submit"'.
Type 'undefined' is not assignable to type '"button" | "reset" | "submit"'. Vue ButonHTMLAttributes Interface for reference export interface ButtonHTMLAttributes extends HTMLAttributes {
autofocus?: Booleanish;
disabled?: Booleanish;
form?: string;
formaction?: string;
formenctype?: string;
formmethod?: string;
formnovalidate?: Booleanish;
formtarget?: string;
name?: string;
type?: 'submit' | 'reset' | 'button'; // It feels like adding | undefined here will suppress the error ?
value?: string | string[] | number;
} |
Bump! |
If you are lucky and have Vue 3.5+, you can use the new Reactive Props Destructure. <script setup lang="ts">
import type { ButtonHTMLAttributes } from 'vue';
interface Props extends ButtonHTMLAttributes {}
const { type = 'button' } = defineProps<Props>();
</script>
<template>
<button :type>
<slot />
</button>
</template> |
Vue version
3.2.37
Link to minimal reproduction
https://sfc.vuejs.org/#eNqdUzuP1DAQ/itWqpx0iREnhBSyuaUAiQaoqNxkk9nFt/FDfgShkP/OOE72QnK6gs6eGX+PmfGQfNQ67z0kRVI6ELqrHVRMElJ+kdq7r16cwJA+E6qF7sCSvu48sITQWKSrYSBTjDw+EpZ42cIZ0+NYUh1LTt45Jcmx6XhzXRDIgbx7w5Lq27WksQCLS7pSgFfbGK4dseC8Jl0tL/jaWXzFJBdaGUcGYuBMRnI2SiA7+mDJLbk2MBfkdBUMtkM5k42S1s02DgGylPHZHzIZ4hLaKr0d7z4ErVEdaknuk8iYiVrnT1ZJbOYQvLM5gZoLMkVCbKIt8PDTOW0LSr3U10veKEGPmKPGS8cFZK0Sx4f8bf7wnrbcunU8Byuyk1G/LNp4Qvj7FTjFYA8mM4CCDZhXyTa1/xBucjvSwDkyOWIDNm3dbxMPBas9arxBXPdjXif3WwNGY9vn9fqfdUBfyAPtbieWIWujtMUhx1F+D7dymswkbJJTkP300WWVhrkvOCC4u8F8wssMk+Jz/Aa6RdnFMyZOKO7XS+B3BekV33Ose4Rci7d0IrqAS/HhHm1ZNIN9MjIazp+VID5ObdoX7GS6FWWd4fLygroFdvklujYWPneqnjGC8JAPjUlf60AsDArG7Uca/wK66Je8
Steps to reproduce
See reproduction link for full example.
I declare a property which allows
undefined
:and actually pass
undefined
:What is expected?
Vue doesn't emit runtime errors for explicitly allowed and used
undefined
properties.What is actually happening?
I get the following Vue runtime error in
dev
modeThis is because the SFC compiler emits the following property declaration. Note how
null
was used instead ofundefined
:If I modify the generated code and runtime like below (see
<<<
and>>>
), to allowundefined
, it seems to work correctly. But I don't understand if there are other reasons for not allowingundefined
to be arequired
property value:System Info
System: OS: Windows Binaries: Node: 18.7.0 npm: 8.15.0 npmPackages: vue: ^3.2.37 => 3.2.37
Any additional comments?
I'm using
undefined
when a value is not set by the user, for example empty number<input>
or unselected<select>
, as I understood to be current recommended practices:The text was updated successfully, but these errors were encountered: