-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
Describe the problem
Sometimes it can be useful to validate or convert the value of a prop before using it.
Some examples :
- convert a string to another type (eg: number).
- replace incorrect values with a default value.
- respect other criteria such as a min/max.
- I want to use a different type internally an externally (ex date string format and Date object)
And of course I would like to keep this responsive and recheck the prop every time it is changed from outside
Currently I see two way to do this.
- If the prop is read-only, I can use a $derived() state :
<script>
let {
// the prop "value" is renamed "propValue" inside the component
value : propValue = 0
} = $props();
// the "propValue" is converted to Number, into a "value" state
const value = $derived(Number(propValue ));
</script>This is fine, even if it involves duplicating the props.
- If the prop is modified inside the component, I have to use a $effect.pre() to validate the value on any update :
let {
value = 0
} = $props();
$effect.pre( () => {
const value_as_number = Number(value);
if (value_as_number !== value) {
value = value_as_number;
}
});
</script>
This solution is more verbose, and the effect is re-executed even when I change the value inside my component (useless).
Describe the proposed solution
I think it would be nice to have a way to replace the prop's default value with a custom function.
Something like this (using a $pipe rune for the exemple - but the name should be reviewed) :
<script>
let {
// when the prop "value" is updated by the caller,
// it will be converted to number
value = $pipe( Number )
} = $props();
</script>The $pipe() rune requires a function as a parameter, which will be used to convert the value of the prop.
There is no default value, it is up to the function to handle the undefined case...
Of course, we should have the same with $bindable(), something like this :
<script>
let {
// when the prop "value" is updated by the caller,
// it will be converted to number
// (and binded to the caller with his new value)
value = $bindable.pipe( Number )
} = $props();
</script>$bindable.pipe() should accept a second function, allowing the reverse conversion to be done when the value is passed back to the caller
<script>
let {
// when the prop "date" is updated by the caller,
// it will be converted to a Date object
// And it will be binded to the caller as an ISO string.
date = $bindable.pipe(
// Date is converted from string to Date
(d)=>new Date(Date.parse(d)),
// Date is binded to caller as string
(d)=>d.toISOString()
)
} = $props();
</script>Caveat :
I don't known how to handle this with TypeScript, as the prop should have two distinct type.
From the caller perspective it should be a string, but in the component it should be a Date
It would be nice to have a simple way to declare this, like something like that :
type Props = {
date: PROP<string, Date>
};But I don't know if it's easily achievable...
Importance
nice to have