Open HoPGoldy opened 3 years ago
This is expected and not related to withDefault()
specifically.
Functions as default value will be executed to get the actual default value. This is useful/needed when the default value should be an fresh object for each component instance, for example.
The solution is to wrap the function in another function:
const props = withDefaults(defineProps<Props>(), {
fetchData: () => defaultFunc
});
Though I can't test it right now and verify that types like that solution as well ...
Ok could test it. Types don't like it.
As a temporary workaround you can typecast it like so:
const props = withDefaults(defineProps<Props>(), {
fetchData: (() => defaultFunc) as unknown as DefaultFunc
});
Thanks for your quick answer!
In general, this truly useful, when I need a string[]
prop, ts will prompt me to set a function for default as a factory.
interface Props {
tags: string[]
}
const props = withDefaults(defineProps<Props>(), {
tags: () => []
});
Along this line of thinking, I think withDefaults
should prompt me to provide a function as the "function factory". But as you can see, withDefaults
wants me to provide a function with exactly same type.
And strangely, when I used the import DefaultFunc
type in props interafce, default function was executed.
import type { DefaultFunc } from './service';
interface Props {
fetchData?: DefaultFunc
}
// props.fetchData print "result" on console
But when I replaced DefaultFunc
with type () => string
, the function was not executed.
interface Props {
fetchData?: () => string
}
// props.fetchData print f() { return "result" } on console
I can't find difference between them.
Functions as default value will be executed to get the actual default value.
In fact,when prop type is Function,vue will not call the default value,see code.
interface Props {
fetchData?: () => string
}
// set default function prop
const props = withDefaults(defineProps<Props>(), {
fetchData: () => '1'
});
The type of fectchData is Function
.So the () => '1'
will not be called.
I can't find difference between them.
import type { DefaultFunc } from './service';
interface Props { fetchData?: DefaultFunc }
This is because In the condition, sfc-compiler can not generate the right type,see [code](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cCBsYW5nPVwidHNcIj5cbmltcG9ydCB7IGRlZmF1bHRGdW5jIH0gZnJvbSAnLi9zZXJ2aWNlJztcbmltcG9ydCB0eXBlIHsgRGVmYXVsdEZ1bmMgfSBmcm9tICcuL3NlcnZpY2UnO1xuXG5pbnRlcmZhY2UgUHJvcHMge1xuICBmZXRjaERhdGE/OiBEZWZhdWx0RnVuY1xufVxuXG5jb25zdCBwcm9wcyA9IHdpdGhEZWZhdWx0cyhkZWZpbmVQcm9wczxQcm9wcz4oKSwge1xuICBmZXRjaERhdGE6IGRlZmF1bHRGdW5jXG59KTtcblxuY29uc29sZS5sb2coJz09PT09PT4gZGVmYXVsdCBwcm9wIGZldGNoRGF0YTonLCBwcm9wcy5mZXRjaERhdGEpO1xuPC9zY3JpcHQ+Iiwic2VydmljZS50cyI6ImV4cG9ydCBjb25zdCBkZWZhdWx0RnVuYyA9IGZ1bmN0aW9uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdyZXN1bHQnXG59XG5cbmV4cG9ydCB0eXBlIERlZmF1bHRGdW5jID0gKCkgPT4gc3RyaW5nIn0=)
In the output js code.You can find that the type of `fetchData` is `null` rather than `Function`
compiler-sfc infers the runtime prop type from your TS Props
interface. When you use an imported type, compiler-sfc currently doesn't crawl external files and thus does not have the type information from the external. So it can only generate a loose runtime type - and because the runtime type is not Function
, the default value will be treated as a factory instead of an actual value.
This is currently a known limitation, the workaround is to prefer writing props types in the same file instead of importing it.
Version
3.2.6
Reproduction link
github.com - vue3-issue-default-function-prop
Steps to reproduce
I have the following functions and the same type definitions in
service.ts
, This function simply returns a string:Then import them in a
setup script
and set props, defaults usingdefineProps
andwithDefault
:call this component and does not pass the prop
fetchData
, then check the console output of the web page.What is expected?
Then console print the function itself:
What is actually happening?
the console prints the return value of the default function, not the function itself.
How to resolve the issue
Passing in the function when the component is called.
Write directly to the type of the default function instead import it:
Then console will print the function itself correctly:
Other ways to trigger the issue
Use
typeof
to get the function type and use it in the props interface:More information
The default prop function in the
<template>
correctly returns the function itself.The same issue occurs when the default prop function return a
Promise
.Here is my
npx envinfo --binaries --system
:yarn create vite
with typescript.