Typescript + Svelte - How to add types to spread component props

Viewed 1352

Is it possible to ensure type safety with components that are composed of others?

eg. if I want to build a special kind of input with certain validation, etc that should extend my base input.

BaseInput.svelte

<script lang="ts">
  export let value = '';
  // + a lot more props
</script>

<input bind:value ... />

AgeInput.svelte - this extends BaseInput

<script lang="ts">
  import BaseInput from './BaseInput.svelte'

  export let {...inputProps}: /* Can we spread and infer BaseInput props? */;
</script>

<BaseInput {...inputProps} type="number" />

Can we infer the BaseInput props?

2 Answers

Svelte builds input type number differently than type type text.

For my side I builded 2 types of inputs to inport.

For inputText.svelte:

<script lang="ts">
  export enum TextType { text = "text", email = "email", password = "password" }

  export let id: string;
  export let type: TextType;
  export let label: string | null = null;
  export let placeholder: string | null = null;
  export let value: string | null = null;

  function typeAction(node: HTMLInputElement) {
    node.type = type
  }

</script>

<div class="textInput">
    <label class="textLabel" for={id}>{label}</label>
  <input on:input bind:value id={id} type="text" placeholder={ placeholder } use:typeAction />
</div>

This function:

 function typeAction(node: HTMLInputElement) {
    node.type = type

is very important to pass type of input:

  export enum TextType { text = "text", email = "email", password = "password" }

And here is an exepmle of my inputNumber.svelte :

<script lang="ts">
    export let id: string;
    export let label: string | null = null;
    export let placeholder: string | null = null;
    export let value: number | null = null;
    export let min: number | null = null;
    export let max: number | null = null;
</script>
  
<div class="numberInput">
  <label class="numberLabel" for={id}>{label}</label>
  <input on:change bind:value id={id} type="number" placeholder={placeholder} min = {min} max = {max} {...$$restProps}/>
</div>

After I import it as usually.

You can use $$props variable of svelte.

app.svelte

<script>
    import AgeInput from './AgeInput.svelte'
</script>

<AgeInput 
    bi_p1="base input prop 1" 
    bi_p2="base input prop 2" 
    ai_p1="age input prop 1" 
    ai_p2="age input prop 2" 
/>

baseinput.svelte

<script lang="ts">
    export let bi_p1;
    export let bi_p2;
  // + a lot more props
</script>

<input />
<pre>
    base input properties
    bi_p1: {bi_p1}
    bi_p2: {bi_p2}
</pre>

ageinput.svelte

<script lang="ts">
  import BaseInput from './BaseInput.svelte';
    
    const {bi_p1, bi_p2, ai_p1, ai_p2, ...restProps} = $$props
</script>

<BaseInput {bi_p1} {bi_p2} type="number" />
<pre>
    age input props
    ai_p1: {ai_p1}
    ai_p2: {ai_p2}
</pre>

Here is the REPL link https://svelte.dev/repl/a22f404887164fc4a5a6d54dfdff1380?version=3.17.2

Related