Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork4.6k
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Class propsThe ability to re-use, type and extend component props — all in one go. IntroductionImagine you have a <scriptlang='ts'module>exportinterfaceBaseProps { value:unknownreadonly required:false }</script><scriptlang='ts'>let { value=bindable(), required=false, ... }:BaseProps=$props()</script>... And we make use of that for a bunch of other components such as <scriptlang='ts'module>import {typeBaseProps,defaultasBase }from'./Base.svelte'interfaceDerivedPropsextendsBaseProps {... }</script><scriptlang='ts'>let { value=bindable(), required=false, ...,...rest }:DerivedProps&HTMLDivElementProps=$props()$effect(()=> {value... })</script><Basebind:value, {required}> <div {...rest}> ... Two things are happening here:
Another downside, is that if we want to "expose" these props via ex. <scriptlang='ts'>import {LogicHandler }from'./logic-handler.svelte.ts'const { value=$bindable(), required=false, ... }:BaseProps=$props()const context= {get value() {returnvalue },set value(v) {value=v },get required() {returnrequired },... }setContext('Base',context)</script> And so we repeat ourselves A LOT. ProposalI propose that we establish a <scriptlang='ts'module>classBaseProps<T>extends$Props { value:T// getter & setterreadonly required:boolean=false// getter }</script> Tip Alternative syntax <scriptlang='ts'module>classBaseProps<T>extendsSvelteProps { value:T=$bindable()readonly required:boolean=false }</script> We'd use this as normal, but having props already be defined as readonly or $bindable. <scriptlang='ts'>typeT=$$Genericconst { value, required }:BaseProps<T>=$props(BaseProps)</script> The idea, however. Is that <scriptlang='ts'>import {LogicHandler }from'./logic-handler.svelte.ts'typeT=$$Genericconst props:BaseProps<T>=$props(BaseProps)const handler=newLogicHandler(props)$effect(()=> {handler.reactiveProperty })setContext('Base',base)</script> A MAJOR shortcut! That's not all. Let's extend this badboy <scriptlang='ts'module>import {BaseProps,defaultasBase }from'./Base.svelte'classDerivedPropsextendsBaseProps {readonly name:string... }</script> We're simply extending the BaseProps, and we include <scriptlang='ts'>const props:DerivedProps&HTMLDivElementProps=$props(DerivedProps)const baseProps=BaseProps.derived(props)/* equivalent to @example const baseProps = { get value() { return props.value }, set value(v) { props.value = v }, get required() { return props.required } }*/basePropsinstanceofBaseProps// true</script><Base {...baseProps}> ... By using additional utility functions target on which element <scriptlang='ts'>const props:DerivedProps&HTMLInputElementProps=$props(DerivedProps)const baseProps=BaseProps.derived(props)const inputProps=DerivedProps.rest(props)// extracts keys not defined within the classes</script><div {...props.$attachments}> <Base {...baseProps}> <inputbind:value={props.value} {...inputProps} /> </Base></div> We now have an impactful, systematically structured, reactive system relating to the props, that we can pass on to various logical classes. It's easy to read, and in my experience levels up the props-game. FurtherCan we go further — should be go further? As an additional sparkling idea, we could via the <scriptlang='ts'module>classPropsextends$Props {// We can a `private` or `protected` property, that acts just like any other Component prop (as discussed so far) #creationDate:Date// We can then define custom getters and setters/** Equivalent to@example$derived(this.#creationDate == undefined || this.#creationDate instanceof Date ? this.#creationDate : new Date(this.#creationDate.toString()))*/get creationDate() {returnthis.#creationDate==undefined||this.#creationDateinstanceofDate?this.#creationDate:newDate(this.#creationDate.toString()) }/** Equivalent to@examplebind:value={...,(value) => value == undefined || value instanceof Date ? value : new Date(value.toString())}*/set creationDate(value) {this.#creationDate=value==undefined||valueinstanceofDate?value:newDate(value.toString()) } }</script> This is last part for custom getters and setters is not core of this proposal. It's an additional way this methodology could benefit the developer with more control. |
BetaWas this translation helpful?Give feedback.