Sunday, 1 October 2023

Composing Svelte Components in JavaScript/TypeScript runtime

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.

  1. How do I fix my code to make it also work without giving defaults to all required props?

  2. 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'})
  1. Is it possible to give default on:click during runtime like how I am doing with props?

Thanks!



from Composing Svelte Components in JavaScript/TypeScript runtime

No comments:

Post a Comment