Hovadko
Hovadko

Reputation: 183

Svelte, infering type from children

I am working on library for forms in svelte 5. My main goal is to have super simple form creation. Right now, the form is defined like this:

<Form bind:form onapprove={handleApprove}>
    <Input key="email" label="email" icon="mail" type="email" />
    <Input key="password" label="password" icon="key" type="password" />
    <Button onclick={() => form.submit()}>Login</Button>
</Form>

When form is submitted and is valid, onapprove event is fired, which can have handler like this:

const handleApprove: OnApprove = async (data) => {
    ...
}

data:

{
    "email": "",
    "password": ""
}

Up to this point, everything works, but there is an issue with typescript. For now, type of data is always:

type FormData = {
    [key: string]: unknown
}

If this will be library one day, I will need full type safety and autocompletion in vscode. I would like the type to by infered from children (<Input /> components). They have key, which is also key in result data, and they have type="text|number|...", so we know if it is a string, number or something else.

Real question is... Is it even possible to infer type of result object from children like this? If so, can I ask for example how to do this?

PS: I have really complex class in background, which handles all kind of things. It is accessible thru form binding on <Form /> component. I am intentionally not posting code of that class, because it is hundreds of lines of code and posting it would make this question too complex.

Upvotes: 0

Views: 33

Answers (2)

Jos&#233; Ram&#237;rez
Jos&#233; Ram&#237;rez

Reputation: 2360

It is true that the parent component (Form) cannot infer the data type based on the children. If you would like to accept brunnerh's answer, by all means do so.

However, I'm here to tell you that you can still do this:

<script lang="ts" generics="TData extends Record<string, unknown>">
    type Props = {
        data: TData;
        onApprove?: (data: TData) => void;
    }

    let {
        data,
        onApprove,
    }: Props = $props();
</script>

...

This code produces a Form component that does provide full Intellisense that is based on the type of the variable used to collect the data. Apologies, I did not make that bindable, but you probably get the idea.

This is how it looks like:

Intellisense Result

Upvotes: 1

brunnerh
brunnerh

Reputation: 185280

This is not possible to my knowledge. Components do not get any static information about children that are added except maybe whether there are any or not.

You could try a similar approach to SvelteKit and automatically generate type declarations based on code analysis. This is probably far from trivial, though, and it makes the library harder to integrate.

Upvotes: 1

Related Questions