Let’s say we have a Button Component that takes props variant: 'primary'|'secondary'
<Button variant='primary' on:click={()=>console.log('hello')}> click </Button>
I want to create a PrimaryButton Component that has all props and actions from Button Component but override the props with default values. I also want to do this without creating a new svelte file.
I was able to get it almost working with the following code
class PrimaryButton extends Button {
constructor(options: ComponentConstructorOptions<Omit<ComponentProps<Button>, 'variant'>>) {
super({...options, props: {variant: 'orange', ...options.props}})
}
}
const PrimaryButton = extendComponent<Button>(Button, {variant: 'orange'})
<PrimaryButton on:click={()=>console.log('yay it works')}>click</PrimaryButton>
Above code gives typescript error if Button Component have other required props that I am not setting a default to.
-
How do I fix my code to make it also work without giving defaults to all required props?
-
How do I create a generic function that does the above so I can use it like the following with correct types.
const PrimaryButton = extendComponent(Button, {variant:'orange'})
I got close but prop types are not working
export function extendComponent<T extends SvelteComponent>(
Comp: ComponentType,
props: Partial<ComponentProps<T>> = {}
) {
return class ExtendedComponent extends Comp {
constructor(options: ComponentConstructorOptions<Omit<ComponentProps<T>, keyof typeof props>>) {
super({...options, props: {...props, ...options.props}})
}
} as unknown as ComponentType<SvelteComponent<Partial<ComponentProps<T>>>>
}
const PrimaryButton = extendComponent<Button>(Button, {variant: 'orange'})
- Is it possible to give default on:click during runtime like how I am doing with props?
Thanks!
2
Answers
To implement a generic function to extend a Svelte component with default props without creating a new file:
extendComponent()
that takes two parameters:extendComponent()
function, simply pass it the component to extend and an object of default props.Here’s how to implement:
extendComponent()
function:extendComponent()
function to create a new component type:Note: It is not possible to give default
on:click
handlers during runtime.You need another generic type argument for the props, otherwise the type will always just be
Partial<ComponentProps<T>>
which has no key information to be extracted.Also, the type of the slots should be extracted, so that information (along with what slot properties are passed in) is not lost. Interestingly there is no existing helper type like
ComponentProps
for that, but it is completely analogous.The full function could look like this:
(Note that this code only works in CSR, in SSR the component provides a
render
function.)There are is no official way to pass events to the constructor. You could either use internals (which can change at any point) or attach them after constructing the instance using
$on
.