vue-cli: Using props in tsx is not possible

Version

3.0.1

Reproduction link

https://github.com/DCzajkowski/vue-jsx-reproduction

Node and OS info

Node v9.11.2 / yarn 1.9.4 / macOS

Steps to reproduce

$ yarn && yarn serve

What is expected?

Compilation successful.

What is actually happening?

An error appears

ERROR in /Users/Darek/web/sites/test2-vue-project/src/views/Home.tsx
9:21 Property 'msg' does not exist on type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Record<string, any>>, Record<string, any>> | ThisTypedComponentOptionsWithArrayProps<Vue, object, object, object, never> | ThisTypedComponentOptionsWithRecordProps<...> | undefined'.
     7 |     return (
     8 |       <div class='home'>
  >  9 |         <HelloWorld msg='Welcome to Your Vue.js   TypeScript App' />
       |                     ^
    10 |       </div>
    11 |     )
    12 |   }
No lint errors found
Version: typescript 3.0.3, tslint 5.11.0
Time: 9742ms

I am very sorry if this is a set-up problem on my side or if it’s not a correct repo to report this kind of stuff. I don’t have experience with TSX and really can’t find a solution to why this may not work. Sorry if it’s a duplicate.

P.S. is https://github.com/vuejs/vue/pull/6856 related?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 22
  • Comments: 22 (4 by maintainers)

Most upvoted comments

I got the same here.

Just created a component

import { Component, Vue, Prop } from 'vue-property-decorator';

@Component()
export default class NavLink extends Vue {

    @Prop()
    public widget!: string;

    @Prop({ default: '#' })
    public href!: string;

    @Prop()
    public toggle!: string;

    protected render(h: any) {
        return (
                <a class='nav-link' data-widget={this.widget} href={this.href} data-toggle={this.toggle}>
                    {this.$slots.default}
                </a>
        );
    }
}

And tried to use it in another one

import { Component, Vue } from 'vue-property-decorator';
import NavLink from '@/components/core/main-header/nav-link/nav-link';

@Component({
    components: {
        'nav-link': NavLink
    },
    name: 'main-header'
})
export default class MainHeader extends Vue {

    public render(h: any) {
        return (
            <NavLink widget='pushmenu'>
                <i class='fa fa-bars'></i>
            </NavLink>
        );
    }
}

Than I got the error

Property 'widget' does not exist on type 'ThisTypedComponentOptionsWithArrayProps<Vue, object, object, object, never> | ThisTypedComponentOptionsWithRecordProps<Vue, object, object, object, object> | ComponentOptions<...> | undefined'.

If instead of the <NavLink widget='pushmenu'> I use <nav-link widget='pushmenu'> it works fine. Or, if the attribute was something-widget instead of just widget, it works fine too.

@Akryum OP has already provided a reproduction link. If it’s out-of-date or so, I just made another one: vue-tsx

you can reproduce by npm install npm run serve and then inpsect the typescript type-check error (the code compiles and works as expected, but the tsc emits an error and so does the VSCode) image

For me the work around was by updating the shims-tsx.d.ts file

import Vue, { VNode } from 'vue';

declare global {
  namespace JSX {
    // tslint:disable no-empty-interface
    interface Element extends VNode {}
    // tslint:disable no-empty-interface
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
      [elem: string]: any;
    }

    // ** Add the following lines to solve the issue **
    interface ElementAttributesProperty{
      $props: {}
    }
  }
}

I know its after a very long time. Just incase someone also fetches the same issue.

I’ve managed to resolve the problem for my scenario using the following pattern [sorry if the guide is a bit longer and not suitable for github, but might help some people having the same problem]

First of all I’ve extended the JSX.ElementAttributesProperty interface and created an abstract Vue extension class to serve as a base for the component. So let’s create a ts file [e.g. vue-tsx.ts] somewhere in your project and place the following in there

import Vue from "vue";

export default abstract class TsxComponent<P> extends Vue {
    private vueTsxProps: Readonly<{}> & Readonly<P>;
}

declare global {
    namespace JSX {
        interface ElementAttributesProperty { vueTsxProps: {}; }
    }
}

Now the component has to be created using following pattern - It’s essential that there’s an interface defined and implemented by the component - ensures the type-safety. This is passed to the TsxComponent base class as a generic argument which creates the dummy vueTsxProps property (see the abstract class above), which is served to the TS typechecker as the valid parameter list. So let’s create a sample component like this

import TsxComponent from "../../vuetsx"; //this is the relative path to the file created above
import { Component, Prop } from 'vue-property-decorator'

interface PersonDataArgs {
    username: string;
    age: number
}

@Component
export default class MyComponent extends TsxComponent<PersonDataArgs> implements PersonDataArgs {
    @Prop() username!: string;
    @Prop() age!: number;

    render() {
        return <span>Hello {this.username}, you are supposed to be {this.age} old</span>
    }
}

Now when using the component, correct type-checking is applied [1st one denied due to missing mandatory property, 2nd one ok, 3rd one denied due to unknown property applied]

image

It makes me crazy to set up a project with typescript and jsx. From now, I should use React if wanna work with jsx. Too many problems

you can run vue add vue-tsx-support and it should configure it for you.

It’s vue add tsx-support, just in case someone wonders, why they get an 404 😃

@brunolau It’s a nice hack, but it forces you to write types and prop declarations twice, which doesn’t seem like a good idea 😕

@Akryum OP has already provided a reproduction link. If it’s out-of-date or so, I just made another one: vue-tsx

you can reproduce by npm install npm run serve and then inpsect the typescript type-check error (the code compiles and works as expected, but the tsc emits an error and so does the VSCode) image

I’ll close this then. Nothing further to do.

I’m not sure that we should solve this within vue-cli.

The state of TSX and Vue 2.* simply is what we see here: without using a lib like vue-tsx-support, TSX won’t work reliably. (sidenote: TSX should work out of the box with Vue 3.)

Seeing as that lib also has a cli-plugin already, I’m not sure we can do much in CLI core to further improve the sitution.

CommentS?

I have been using this library to great success, you can get typechecking for both props and events. https://github.com/wonderful-panda/vue-tsx-support

There is also a vue-cli-plugin to configure it for you.

import * as tsx from 'vue-tsx-support'

const Foo = tsx.component({
  name: 'Foo',

  props: {
    msg: {
      type: String,
      required: true as true
    }
  },

  render() {
    return (
      <span>Hi</span>
    )
  }
})

const Test = {
  name: 'Test',

  components: {
    Foo
  },

  render() {
    return (
      <div>
        <Foo  /> // ERROR since you did not provide the props
      </div>
    )
  }
}