vuejs / core

đź–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.6k stars 8.32k forks source link

TSX with dynamic element name results in "TS2322: Type '{ class: string; }' is not assignable to type 'ReservedProps'." #5666

Open lloydjatkinson opened 2 years ago

lloydjatkinson commented 2 years ago

Version

3.2.31

Reproduction link

github.com

Steps to reproduce

Using Vue CLI create a Vue 3 + TS(X) project.

Create a component with the following where as is a string prop:

    render () {
        const Element = this.as;

        return (
            <Element class={this.styles}>
                {this.$slots.default && this.$slots.default()}
            </Element>
        );
    },

What is expected?

That we can create an element tag dynamically based on a value

What is actually happening?

TS2322: Type '{ class: string; }' is not assignable to type 'ReservedProps'.
  Property 'class' does not exist on type 'ReservedProps'.
    228 |
    229 |         return (
  > 230 |             <Element class={this.styles}>
        |                      ^^^^^
    231 |                 {this.$slots.default && this.$slots.default()}
    232 |             </Element>
    233 |         );

I also tried to use <component is={this.as}> which simply results in the literal value <component> being rendered in the DOM. Trying <Component> results in Cannot find name "Component". By the way, the SFC playground does not support TSX files.

LinusBorg commented 2 years ago

@pikax can you take a look at this one? Thanks!

rudyxu1102 commented 1 year ago

Just use lower-case element instead of Element.

image

sevilyilmaz commented 1 year ago

@LinusBorg, I'm bumping this up.

When I use the lower-case approach suggested above, it actually works (with vite build, vitest and vue-loader) but then VS Code complains about a constant is declared but never used. It seems that this needs a proper solution instead of a workaround.

image

yxw007 commented 5 months ago

Version

3.2.31

Reproduction link

github.com

Steps to reproduce

Using Vue CLI create a Vue 3 + TS(X) project.

Create a component with the following where as is a string prop:

    render () {
        const Element = this.as;

        return (
            <Element class={this.styles}>
                {this.$slots.default && this.$slots.default()}
            </Element>
        );
    },

What is expected?

That we can create an element tag dynamically based on a value

What is actually happening?

TS2322: Type '{ class: string; }' is not assignable to type 'ReservedProps'.
  Property 'class' does not exist on type 'ReservedProps'.
    228 |
    229 |         return (
  > 230 |             <Element class={this.styles}>
        |                      ^^^^^
    231 |                 {this.$slots.default && this.$slots.default()}
    232 |             </Element>
    233 |         );

I also tried to use <component is={this.as}> which simply results in the literal value <component> being rendered in the DOM. Trying <Component> results in Cannot find name "Component". By the way, the SFC playground does not support TSX files.

const CustomComp = defineComponent({
    name: "CustomComp",
    setup(props) {

        const HelloWord = defineComponent(() => {
            return () => <span class="text-primary font-bold">HelloWord</span>
        })

        return () => (
            <HelloWord class={['text-red']}></HelloWord>
        )
    }
});

This writing works for me, share with you