Type `() => boolean` is not assignable type `boolean` when using `withDefault` with a factory function
Vue version
3.2.47
Link to minimal reproduction
.
Steps to reproduce
Type '() => boolean' is not assignable to type 'boolean | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false) | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { ...; }>) => true) | undefined'. Type '() => boolean' is not assignable to type '(props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false'.
Not sure why there is a type error on hwAcceleration
but not duration
if it's invalid.
export interface Props {
expanded: boolean;
duration?: number;
hwAcceleration?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
expanded: false,
duration: () => inject<PluginOptions>(PLUGIN_KEY)?.duration || 300,
hwAcceleration: () => inject<PluginOptions>(PLUGIN_KEY)?.hwAcceleration || false,
});
Changing the interface to this solve the type error, but it seems wrong.
The type of the value is still boolean
, the fact that Vue need a factory function in withDefaults
doesn't change the nature of the value, is this a bug with withDefaults
?
export interface Props {
expanded: boolean;
duration?: () => number;
hwAcceleration?: () => boolean;
}
What is expected?
It shouldn't be required from the Vue documentation. Reference: https://vuejs.org/api/sfc-script-setup.html#default-props-values-when-using-type-declaration.
export interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
What is actually happening?
Type '() => boolean' is not assignable to type 'boolean | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false) | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { ...; }>) => true) | undefined'. Type '() => boolean' is not assignable to type '(props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false'.
System Info
No response
Any additional comments?
No response
If I add a // @ts-ignore
and check the built code.
I see this, which seems perfectly fine.
{
expanded: { type: Boolean, required: !0, default: !1 },
duration: {
type: Number,
required: !1,
default: () => {
var e;
return ((e = i(s)) == null ? void 0 : e.duration) || 300;
},
},
hwAcceleration: {
type: Boolean,
required: !1,
default: () => {
var e;
return ((e = i(s)) == null ? void 0 : e.hwAcceleration) || !1;
},
},
}
@LinusBorg @yyx990803 How are pending PR reviewed/managed ? Any chance that this will get merged with 3.3 ?
@LinusBorg @yyx990803 Sorry to ping again, but any idea when this could get merged ? I would be sad to have to wait another 2 years like we did between 3.2 and 3.3
EDIT: I just realized that the withDefaults macro is documents to remove undefined from the defaulted props; however, in my use case the function used for the default value can return a value OR undefined, depending on circumstances, where undefined is a perfectly valid value meaning "unused". Perhaps withDefaults is just not appropriate for this use case? Original comment follows:
I don't know if this is related, but if a prop is optional, returning undefined from a function also triggers a type error, even though doing the same in the options API is fine (and the only way to positively assign undefined as the default value).
e.g., given:
interface Props {
opt?: string
}
Then:
const props: Props = defineProps({
opt: String,
required: false,
default: () => undefined
})
works fine, but:
const props = withDefaults(defineProps<Props>(), {
opt: () => undefined
})
causes a type error:
Type '() => undefined' is not assignable to type 'InferDefault<Props, string | undefined> | undefined'.
Type '() => undefined' is not assignable to type '(props: Props) => string'.ts(2322)
@nborko Well, in your first exemple the opt
props is optional opt?: string
. But in your second the props is not (you ommited the ?
).
You code should be this:
const props = withDefaults(defineProps<Props>(), {
opt?: () => undefined
})
Closing this issue since it's working on the latest version, playground