Skip to content

Error when referencing props in component class or component methods from watchers #220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tobiasheldring opened this issue Feb 6, 2018 · 12 comments

Comments

@tobiasheldring
Copy link

tobiasheldring commented Feb 6, 2018

To Reproduce

Create a new project with vue-cli and select Typescript and Class components as features

update HelloWorld.vue script section to

<script lang="ts">
import Vue from "vue"
import Component from "vue-class-component"

@Component({
  props: {
    msg: String
  },
  watch: {
    msg: function () {
      this.printMessage()
    }
  }
})
export default class HelloWorld extends Vue {
  printMessage() {
    console.log(this.msg)
  }
}
</script>

Compile error

ERROR in /Users/tohe/Projects/test-class-component/src/components/HelloWorld.vue
40:12 Property 'printMessage' does not exist on type 'Vue'.
    38 |   watch: {
    39 |     msg: function () {
  > 40 |       this.printMessage()
       |            ^
    41 |     }
    42 |   }
    43 | })
ERROR in /Users/tohe/Projects/test-class-component/src/components/HelloWorld.vue
46:22 Property 'msg' does not exist on type 'HelloWorld'.
    44 | export default class HelloWorld extends Vue {
    45 |   printMessage() {
  > 46 |     console.log(this.msg)
       |                      ^
    47 |   }
    48 | }
    49 | </script>

Versions

vue-cli 2.9.3
vue-class-component 6.1.2

@ktsn
Copy link
Member

ktsn commented Feb 6, 2018

Please declare the props type as class properties and annotate your component type on @Component decorator or use vue-property-decorator.

<script lang="ts">
import Vue from "vue"
import Component from "vue-class-component"

@Component<HelloWorld>({
  props: {
    msg: String
  },
  watch: {
    msg: function () {
      this.printMessage()
    }
  }
})
export default class HelloWorld extends Vue {
  msg: string

  printMessage() {
    console.log(this.msg)
  }
}
</script>

@ktsn ktsn closed this as completed Feb 6, 2018
@KaelWD
Copy link

KaelWD commented Apr 16, 2018

The readme makes it look like you can use props from the decorator without having to declare them twice:
image

Obviously this won't work because of microsoft/TypeScript#4881, but it is pretty misleading.

@ktsn
Copy link
Member

ktsn commented Apr 16, 2018

The example in readme is written in JavaScript. If you want to see TS example, please see example directory in this repo.

@KaelWD
Copy link

KaelWD commented Apr 16, 2018

Ah, right. I forgot it was for babel too. Do you think this is a decent way to do it without the double declaration?

const options = Vue.extend({
  props: {
    foo: String,
    bar: Boolean
  }
})

@Component
export default class FooBar extends options {
  ...
}

@ktsn
Copy link
Member

ktsn commented Apr 16, 2018

Oh, it looks really nice idea 👍
Maybe we should update TypeScript example to use that way.

@ru-sh
Copy link

ru-sh commented May 6, 2018

It doesn't work

import Component from "vue-class-component";
import Vue from "vue";

const Props = Vue.extend({
  props: {
    items: {
      type: Array,
      default: () => []
    },
    selectedItems: {
      type: Array,
      default: () => []
    },
    keyFunc: {
      type: Function,
      default: () => {
        return i => i;
      }
    }
  }
});

@Component({
  model: {
    prop: "selectedItems",
    event: "update"
  }
})
export default class CheckboxGroup extends Props {
  selected = this.selectedItems;

  get selectAll(): boolean {
    return this.items ? this.selectedItems.length == this.items.length : false;
  }
  set selectAll(value: boolean) {
    var selected: any[] = [];
    debugger;
    if (value) {
      selected = [...this.items];
    } else {
      selected = [];
    }

    this.update(selected);
  }

  update(items: any[]) {
    this.$emit("update", items);
  }

  itemClick(el: any) {
    let item = el.value;
    let items = (this as any).selectedItems.concat([item]);
    (this as any).update(items);
  }

  isChecked(item: any) {
    let ch = (this as any).selectedItems.filter(i => i === item);
    return ch.length;
  }
}
error  in .\src\components\CheckboxGroup.vue.ts

[tsl] ERROR in .\src\components\CheckboxGroup.vue.ts(47,19)
      TS2339: Property 'selectedItems' does not exist on type 'CheckboxGroup'.

 error  in .\src\components\CheckboxGroup.vue.ts

[tsl] ERROR in .\src\components\CheckboxGroup.vue.ts(50,17)
      TS2339: Property 'items' does not exist on type 'CheckboxGroup'.

 error  in .\src\components\CheckboxGroup.vue.ts

[tsl] ERROR in .\src\components\CheckboxGroup.vue.ts(50,30)
      TS2339: Property 'selectedItems' does not exist on type 'CheckboxGroup'.

 error  in .\src\components\CheckboxGroup.vue.ts

[tsl] ERROR in .\src\components\CheckboxGroup.vue.ts(50,59)
      TS2339: Property 'items' does not exist on type 'CheckboxGroup'.

 error  in .\src\components\CheckboxGroup.vue.ts

[tsl] ERROR in .\src\components\CheckboxGroup.vue.ts(56,27)
      TS2339: Property 'items' does not exist on type 'CheckboxGroup'.

@jannikkeye
Copy link

This does indeed not work, how did this make it into the docs? Am I missing something here.

@LukasBombach
Copy link

yep, does not work. you're either stuck with:

@Component({
  props: {
    id: Number,
  }
})
export default class SomeComponent extends Vue {
  public id: number;
}

Property 'id' has no initializer and is not definitely assigned in the constructor.

or

@Component({
  props: {
    id: Number,
  }
})
export default class SomeComponent extends Vue {
  public id: number = -1; // initialize variable
}

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "id"

@LukasBombach
Copy link

LukasBombach commented Oct 6, 2018

Oh, I just found a fix. Do this:

export default class LightSwitch extends Vue {
  @Prop()
  public id!: number;
}

don't miss the ! after id

@plh97
Copy link

plh97 commented Aug 26, 2019

not fix it.

@putrasurya
Copy link

Oh, I just found a fix. Do this:

export default class LightSwitch extends Vue {
  @Prop()
  public id!: number;
}

don't miss the ! after id

please explain why

@joker7blue
Copy link

export default class LightSwitch extends Vue {
  @Prop()
  public id!: number;
}

It's word very well, thank you so much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants