How to register functional component

Viewed 89

I have a functional compopnent in dialog-functional.tsx

import { Slot } from 'vue';

export interface IDialog {
    background: string;
    alignRight: boolean;
};

type TSlotNames = 'default' | 'header' | 'footer';
type TDialogSlots = Readonly<Record<TSlotNames, Slot | undefined>>;
export default (props: { info: IDialog}, {slots}: {slots: TDialogSlots}) => {
    return <div>
        {/* header */}
        <h1>Дијалог: {slots?.header?.()} </h1>


        {/* body */}
        <div style={{
            "background-color" : props.info?.background ?? undefined,
            "text-align": props.info?.alignRight ? "right" : undefined,
        }}>
            <div>Садржај:</div>
            { slots?.default?.() }
            <div>
                info: { JSON.stringify(props.info)}
            </div>
        </div>

        <hr/>

        {/* footer */}
        <div>
            Подножје: {slots?.footer?.()}
        </div>
    </div>
}

and I use it in test-demo.tsx:

import { defineComponent } from 'vue';
import csfDialog, { IDialog } from "./dialog-functional";

const proba = {
    title: "Проба, аха",
};

const dlgInfo: IDialog = {
    background: '#ffaaaa',
    alignRight: true,
}

export default defineComponent({
    // https://stackoverflow.com/a/64115658
    components: {
        csfDialog,
    },
  render() {
    // use an array to return multiple root nodes
    return <div>
        <h1>Дијалог (with "v-slots"):</h1>
        <csfDialog info={dlgInfo} v-slots={
            {
                footer: () => <div>Садржај <b>подножја</b></div>,
                header: () => `Наслов`
            }
        }>
            Ово је основни садржај са <b>анотацијом</b> гдје год треба
        </csfDialog>
        </div>
  }
})

However I get an error when registering the functional component csfDialog with:

export default defineComponent({
    components: {
        csfDialog,
    },
    // ...
}
No overload matches this call.
  The last overload gave the following error.
    Type '(props: {    info: IDialog;}, { slots }: { slots: TDialogSlots; }) => JSX.Element' is not assignable to type 'Component<any, any, any, ComputedOptions, MethodOptions>'.ts(2769)

NOTE 1

If I cast it into a Vue Component it works fine:

import { Component } from 'vue';

export default defineComponent({
    components: {
        csfDialog: (csfDialog as unknown) as Component,
    },
    // ...
}

NOTE 2

It seems that if the functional component is imported with the .jsx extension (even though it has .tsx extension):

// import csfDialog, { IDialog } from "./dialog-functional";
import csfDialog, { IDialog } from "./dialog-functional.jsx";
``

The types will be better recognized but I cannot enumerate slots anymore, as I get error:

Types of property 'slots' are incompatible. Type 'Readonly' is missing the following properties from type 'Readonly<Record<TSlotNames, Slot | undefined>>': default, header, footerts(2769)


so I have to reduce typings:

```ts
import { Slot, Slots } from 'vue';

// ...

export default (props: { info: IDialog}, {slots}: {slots: Slots}) => {
// ...
}

With this I have no errors anymore, but

  1. awkard file extension issue .tsx -> .jsx (I assume something with JSX/Vue management of TS imports)
  2. not being able to strict slots anymore
0 Answers
Related