Git Product home page Git Product logo

vue-property-decorator's Introduction

[DEPRECATED] Vue Property Decorator

⚠️ Notice

This library is no longer actively maintained. If you still want to use classes, check out the community-maintained project vue-facing-decorator.


npm Build Status

This library fully depends on vue-class-component, so please read its README before using this library.

License

MIT License

Install

npm i -S vue-property-decorator

Usage

There are several decorators and 1 function (Mixin):

See also

vuex-class

@Prop(options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Prop(Number) readonly propA: number | undefined
  @Prop({ default: 'default value' }) readonly propB!: string
  @Prop([String, Boolean]) readonly propC: string | boolean | undefined
}

is equivalent to

export default {
  props: {
    propA: {
      type: Number,
    },
    propB: {
      default: 'default value',
    },
    propC: {
      type: [String, Boolean],
    },
  },
}

If you'd like to set type property of each prop value from its type definition, you can use reflect-metadata.

  1. Set emitDecoratorMetadata to true.
  2. Import reflect-metadata before importing vue-property-decorator (importing reflect-metadata is needed just once.)
import 'reflect-metadata'
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class MyComponent extends Vue {
  @Prop() age!: number
}

Each prop's default value need to be defined as same as the example code shown in above.

It's not supported to define each default property like @Prop() prop = 'default value' .

@PropSync(propName: string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @PropSync('name', { type: String }) syncedName!: string
}

is equivalent to

export default {
  props: {
    name: {
      type: String,
    },
  },
  computed: {
    syncedName: {
      get() {
        return this.name
      },
      set(value) {
        this.$emit('update:name', value)
      },
    },
  },
}

@PropSync works like @Prop besides the fact that it takes the propName as an argument of the decorator, and also creates a computed getter and setter behind the scenes. This way you can interface with the property as if it was a regular data property whilst making it as easy as appending the .sync modifier in the parent component.

@Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Model('change', { type: Boolean }) readonly checked!: boolean
}

is equivalent to

export default {
  model: {
    prop: 'checked',
    event: 'change',
  },
  props: {
    checked: {
      type: Boolean,
    },
  },
}

@Model property can also set type property from its type definition via reflect-metadata .

@ModelSync(propName: string, event?: string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @ModelSync('checked', 'change', { type: Boolean })
  readonly checkedValue!: boolean
}

is equivalent to

export default {
  model: {
    prop: 'checked',
    event: 'change',
  },
  props: {
    checked: {
      type: Boolean,
    },
  },
  computed: {
    checkedValue: {
      get() {
        return this.checked
      },
      set(value) {
        this.$emit('change', value)
      },
    },
  },
}

@ModelSync property can also set type property from its type definition via reflect-metadata .

@Watch(path: string, options: WatchOptions = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Watch('child')
  onChildChanged(val: string, oldVal: string) {}

  @Watch('person', { immediate: true, deep: true })
  onPersonChanged1(val: Person, oldVal: Person) {}

  @Watch('person')
  onPersonChanged2(val: Person, oldVal: Person) {}

  @Watch('person')
  @Watch('child')
  onPersonAndChildChanged() {}
}

is equivalent to

export default {
  watch: {
    child: [
      {
        handler: 'onChildChanged',
        immediate: false,
        deep: false,
      },
      {
        handler: 'onPersonAndChildChanged',
        immediate: false,
        deep: false,
      },
    ],
    person: [
      {
        handler: 'onPersonChanged1',
        immediate: true,
        deep: true,
      },
      {
        handler: 'onPersonChanged2',
        immediate: false,
        deep: false,
      },
      {
        handler: 'onPersonAndChildChanged',
        immediate: false,
        deep: false,
      },
    ],
  },
  methods: {
    onChildChanged(val, oldVal) {},
    onPersonChanged1(val, oldVal) {},
    onPersonChanged2(val, oldVal) {},
    onPersonAndChildChanged() {},
  },
}

@Provide(key?: string | symbol) / @Inject(options?: { from?: InjectKey, default?: any } | InjectKey) decorator

import { Component, Inject, Provide, Vue } from 'vue-property-decorator'

const symbol = Symbol('baz')

@Component
export class MyComponent extends Vue {
  @Inject() readonly foo!: string
  @Inject('bar') readonly bar!: string
  @Inject({ from: 'optional', default: 'default' }) readonly optional!: string
  @Inject(symbol) readonly baz!: string

  @Provide() foo = 'foo'
  @Provide('bar') baz = 'bar'
}

is equivalent to

const symbol = Symbol('baz')

export const MyComponent = Vue.extend({
  inject: {
    foo: 'foo',
    bar: 'bar',
    optional: { from: 'optional', default: 'default' },
    baz: symbol,
  },
  data() {
    return {
      foo: 'foo',
      baz: 'bar',
    }
  },
  provide() {
    return {
      foo: this.foo,
      bar: this.baz,
    }
  },
})

@ProvideReactive(key?: string | symbol) / @InjectReactive(options?: { from?: InjectKey, default?: any } | InjectKey) decorator

These decorators are reactive version of @Provide and @Inject. If a provided value is modified by parent component, then the child component can catch this modification.

const key = Symbol()
@Component
class ParentComponent extends Vue {
  @ProvideReactive() one = 'value'
  @ProvideReactive(key) two = 'value'
}

@Component
class ChildComponent extends Vue {
  @InjectReactive() one!: string
  @InjectReactive(key) two!: string
}

@Emit(event?: string) decorator

The functions decorated by @Emit $emit their return value followed by their original arguments. If the return value is a promise, it is resolved before being emitted.

If the name of the event is not supplied via the event argument, the function name is used instead. In that case, the camelCase name will be converted to kebab-case.

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

@Component
export default class YourComponent extends Vue {
  count = 0

  @Emit()
  addToCount(n: number) {
    this.count += n
  }

  @Emit('reset')
  resetCount() {
    this.count = 0
  }

  @Emit()
  returnValue() {
    return 10
  }

  @Emit()
  onInputChange(e) {
    return e.target.value
  }

  @Emit()
  promise() {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(20)
      }, 0)
    })
  }
}

is equivalent to

export default {
  data() {
    return {
      count: 0,
    }
  },
  methods: {
    addToCount(n) {
      this.count += n
      this.$emit('add-to-count', n)
    },
    resetCount() {
      this.count = 0
      this.$emit('reset')
    },
    returnValue() {
      this.$emit('return-value', 10)
    },
    onInputChange(e) {
      this.$emit('on-input-change', e.target.value, e)
    },
    promise() {
      const promise = new Promise((resolve) => {
        setTimeout(() => {
          resolve(20)
        }, 0)
      })

      promise.then((value) => {
        this.$emit('promise', value)
      })
    },
  },
}

@Ref(refKey?: string) decorator

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

import AnotherComponent from '@/path/to/another-component.vue'

@Component
export default class YourComponent extends Vue {
  @Ref() readonly anotherComponent!: AnotherComponent
  @Ref('aButton') readonly button!: HTMLButtonElement
}

is equivalent to

export default {
  computed() {
    anotherComponent: {
      cache: false,
      get() {
        return this.$refs.anotherComponent as AnotherComponent
      }
    },
    button: {
      cache: false,
      get() {
        return this.$refs.aButton as HTMLButtonElement
      }
    }
  }
}

@VModel(propsArgs?: PropOptions) decorator

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

@Component
export default class YourComponent extends Vue {
  @VModel({ type: String }) name!: string
}

is equivalent to

export default {
  props: {
    value: {
      type: String,
    },
  },
  computed: {
    name: {
      get() {
        return this.value
      },
      set(value) {
        this.$emit('input', value)
      },
    },
  },
}

vue-property-decorator's People

Contributors

304notmodified avatar agentschmitt avatar akoidan avatar angeart avatar artemsky avatar carterli avatar cexbrayat avatar cherishit avatar davidespinola avatar debiancc avatar dependabot[bot] avatar eddow avatar evertt avatar fsx950223 avatar gmoneh avatar jovey-zheng avatar kaorun343 avatar lmillucci avatar lx1036 avatar magiccwl avatar mrjmpl3 avatar mugi-uno avatar nacasha avatar oguimbal avatar robula avatar smithki avatar sobolevn avatar sylvainpolletvillard avatar vlad-ro avatar wangzongxu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-property-decorator's Issues

Breaking my jest tests...

I'm using ts-jest, if it's relevant. When I use the Vue export from vue-property-decorator, I get:

TypeError: Object prototype may only be an Object or null: undefined
        at setPrototypeOf (native)

This doesn't happen when I use the export from vue itself.

Object.assign

Decorator @watch will fail in es5 browers (IE11) because Object.assign is not supported without polyfill?

AMD Support

Looking at the tsconfig.json here, seems that the only module load pattern supported is CommonJs.

I'm trying to develop a boilerplate using this library but, I cannot require it in a Web view using requirejs.

As you can see from the vue-class-compoment project (build folder), the definition is in UMD style factory (checking for define.amd etc...).

Ps. Thank you for the great job here...seriously.

Warnings inside .ts files

I took the <script lang="ts"> portion of MyComponent.vue and pasted it into a .ts file:
image

I get the following errors:

image

How to validate that a prop implements a certain typescript interface

Imagine I have following typescript vue component class

export default class MyClass extends Vue {

  @Prop
  MyCollection: MyModel[];

It seems not to be the case that the incoming type MyModel[] is validated.

What do you suggest to get this working? Could a custom validator help?
Thanks.

Proposal: @Emit decorator

Hello there,

I have used this library on many Vue projects and cannot do without it anymore. Thanks a lot for your great work !

I would like to suggest a new decorator @Emit that would be very handy from my experience. It is used to explicitely declare all the custom events a component might emit.

Example

 @Component({
    template: `<button @click.left="increment(1)" @click.right="resetCount">{{count}}</button>`
 })
class ButtonCounter extends Vue {
  count: number;
   
  constructor(){
    this.count = 0;
  }

  @Emit('reset') resetCount(){
    this.count = 0;
  }
  
  @Emit() increment(n: number){ 
    this.count += n
  }
}
<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter @increment="incrementTotal" @reset="resetTotal"></button-counter>
  <button-counter @increment="incrementTotal" @reset="resetTotal"></button-counter>
</div>

Benefits

  • makes more explicit and straight-forward to list all the custom events that a component might emit
  • let you add type definitions on the arguments sent with the events
  • use a method reference instead of the event name as a String, useful for refactoring / autocomplete / prevent typos
  • simplify a common pattern where a component method is used to emit a custom event while doing simple changes on the component state.

Possible caveats

  • the linter can complain about unused arguments in the method body

Implementation

The general idea of the Emit decorator is to wrap around a method so that it emits a custom event with the arguments received by the method, at the end of the method execution.

Suggestion from @eddow ( #44 ) : If the method explicitlely returns false, no event is emtted.

I started to work on it, but struggle to make the tests pass with the runtime-only version of Vue that is used in the tests. Here is the current state : sylvainpolletvillard@692e7ec

Before I go further, I would like to know if you think this is a good idea.

watch question

would something like

 @Watch('$route.path')
    onChildChanged(val: string, oldVal: string) 
    { //this.$route.
      console.log("watch call "+val);
    }

be possible? currently not watched, without immediate, so that watch is just on particular property? just to make the notation short as possible..

Data Decorator

May you create a Data Decorator (annotation)?
If I create a vue data attribute in my decorated (@component) class, it will only be build if it has a default value, otherwise it won't.

Using child components breaks props?

Hi,

When I try to use a child component, my prop doesn't get populated so I end up with the following error:

Property or method "section" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Error in render function: "TypeError: Cannot read property 'name' of undefined"

With this code:

Parent Template:
<section-component v-for="section in page.sections" :key="section.id" :section="section"> </section-component>
Code:

import Vue from 'vue';
import { Component, Prop, Watch } from 'vue-property-decorator';
import { Section } from '../../models/models';

@Component({
    name: 'section-component',
    components: {
        QuestionComponent: require('../question/question.vue')
    }
})
export default class SectionComponent extends Vue {
    @Prop()
    section: Section;
}

However, if I remove the components part from Component decorator. My section-component renders but I'm unable to access my question-component:

import Vue from 'vue';
import { Component, Prop, Watch } from 'vue-property-decorator';
import { Section } from '../../models/models';

@Component({
    name: 'section-component'
})
export default class SectionComponent extends Vue {
    @Prop()
    section: Section;
}

Any ideas on what I can do to resolve this? Thanks

Compile error with Typescript 2.4

When doing this:

@Prop(String)
name: string;

Typescript 2.4 reports a type error. It's probably necessary to extend the Prop parameter type from PropOptions | Constructor[] to

PropOptions | Constructor[] | Contructor

Need to implement vue-router navigation guards

I'm implementing a beforeRouteUpdate vue-router guard. This is not documented in vue-property-decorator and when I ran into issues I wasn't sure the guards are supported.

I had to look up documentation in vue-class-component. The guards are working now, but could you document setup for vue-property-decorator?

Also, registration in Component has to happen in a component file. Most of global setup I do happens in the main Vue instance file, but this registration doesn't work there.

// Register the router hooks
Component.registerHooks([
  "beforeRouteEnter",
  "beforeRouteUpdate",
  "beforeRouteLeave"
]);

noImplicitAny: Could not find a declaration file

When importing, eg

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

with

"noImplicitAny": true

I get the following error:

[tsl] ERROR in /components/Board/Sum.vue.ts(8,38)
      TS7016: Could not find a declaration file for module 'vue-property-decorator'. '/node_modules/vue-property-decorator/lib/vue-property-decorat
or.umd.js' implicitly has an 'any' type.
  Try `npm install @types/vue-property-decorator` if it exists or add a new declaration (.d.ts
) file containing `declare module 'vue-property-decorator';`

On the other hand, clicking on the module name in VSCode takes me to lib/vue-property-decorator.d.ts

And everything works correctly with noImplicitAny: false

Finally, allowSyntheticDefaultImports has no effect, although vuejs/vue-class-component#usage claims that it needs to be true

Using this keyword in Prop validator

I'm unable to use the this keyword inside a @Prop validator. Here is an example of what I'm trying to do:

  @Prop({
    default: 0,
    type: Number,
    validator: (x) => x >= this.minValue && x <= this.maxValue,
  })
  public value: number;

  @Prop({
    default: 100,
    type: Number,
  })
  public maxValue: number;

  @Prop({
    default: 0,
    type: Number,
  })
  public minValue: number;

The error I get from TypeScript is:

'this' implicitly has type 'any' because it does not have a type annotation.

Name for component?

Not sure if we are doing something wrong or is a bug on vue, let me explain:

When we create a component we usually add 'Component' to the name, for example:
export class SwitchButtonBoxComponent extends SwitchButtonComponent {}

When we add this component to his parent the only way that we've found to change his tag name is:

@Component({
    components: {
        'switch-button-box': SwitchButtonBoxComponent
    }
})

We have to do that because we don't want the 'Component' word on the tag name (I think is a normal thing)

But this is not the best scenario, we've tried that:

export class SwitchButtonBoxComponent extends SwitchButtonComponent {
     name: 'switch-button-box'
}

and on the other side

@Component({
    components: {
        SwitchButtonBoxComponent
    }
})

But is not working, is there any alternative or suggestion?

Thanks!

@Inject example with provide ?

Hi,

First of all, thanks for this awesome library! I wonder, if you can provide a bit more details on the @Inject decorator or not. I suspect this decorator is paired with the provide option. However, the README.md file doesn't clearly mention it.

Cheers,

Usage example broken

I think that your example needs to extend Vue, ie:

import { Component, prop, watch } from 'vue-property-decorator';
import * as Vue from 'vue';

@Component export class CompOne extends Vue{
    @prop(Number)
    propA: number;

    @prop({
      type: String,
      default: 'default value'
    })
    propB: string;

    @watch('child')
    onChildChanged(val: string, oldVal: string) {}
}

Using @Provide and @Inject on Simple Classes Instead of Components

In theory I can do something like this, according to the documentation:

    import { Component, Inject, Provide, Vue } from 'vue-property-decorator'
    
    const s = Symbol('baz')
    
    @Component
    export class MyComponent extends Vue {
      @Provide() foo = 'foo'
      @Provide('bar') baz = 'bar'

      @Inject() foo: string
      @Inject('bar') bar: string
      @Inject(s) baz: string
    }

However, what if I want to use @Provide and @Inject on a class that is not a component? For example, if I have ComponentA that depends on ServiceA that depends on ServiceB. How can i set this up?

A Simple @Inject Example

I'm trying to understand how @Inject works. I've looked at the example and I can't quite grasp how to use it. I'd like to inject an instance of an arbitrary class into my vue component. Could someone post a super simple example of how to do this?

require("reflect-metadata");

I'm implementing Inversify for IoC and DI in my Vue project, and discovered that Vue Property Decorator has require("reflect-metadata"); in its entry point, so I can't import it in my polyfills, but I need to load it before I can use Inversify, and I need to use Inversify before Vue Property Decorator has loaded. How can I get around this, or can you do something on your end to remove it and advise people to add it to their polyfills themselves?

Thanks

@Inject decorate usage with provide

Hi,

As a follow-up question from #11 , I wonder if this is correct approach or not.

Foo.ts

class Foo {
  public bar: string = "Hello World";
}

export default Foo;

ParentComponent.vue:

<template>
  <child-component></child-component>
</template>

<script language="ts">
import Vue from "vue";
import { Component } from "vue-property-decorator";
import Foo from "./Foo";
import ChildComponent from "./ChildComponent.vue";

let foo = new Foo();

@Component({
  name: "Parent",
  components: {
    childComponent: ChildComponent
  },
  provide: foo
})
export default class ParentComponent extends Vue {
}
</script>

ChildComponent.vue:

<template>
  <p>{{ foo.bar }}</p>
</template>

<script language="ts">
import Vue from "vue";
import { Component, Inject } from "vue-property-decorator";
import Foo from "./Foo";

@Component({
  name: "Child"
})
export default class ChildComponent extends Vue {
  @Inject(Symbol("Foo"))
  public foo: Foo;

  created(): void {
    console.log(this.foo.bar);
  }
}
</script>

When I ran this code, this.foo in the ChildComponent is undefined. In other words, the Foo instance has not been properly injected from ParentComponent. Could you confirm that I used both provide/inject pair properly?

Cheers,

Put the returned value of @Emit decorated function to arguments

Is it a good idea to put the returned value as one of the arguments for $emit()? e.g.

descriptor.value = function emitter(...args: any[]) {
       this.$emit(event || key, ...args, original.apply(this, args));
}

Most of time we want to emit the value returned from the function. How do you think?

[Webpack WARNING] critical dependency

Environment

OS: CentOS 7.3
node: v6.10.3
npm: 3.10.10
vue-property-decorator: 5.2.0
webpack: 3.3.0

Test

karma: 1.7.0
phantomjs: 2.1.14

when i test, i got this message:

WARNING in ./node_modules/vue-property-decorator/lib/vue-property-decorator.js
4:24-31 Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
webpack: Compiled with warnings.
25 07 2017 14:07:43.501:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/
25 07 2017 14:07:43.507:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
25 07 2017 14:07:43.522:INFO [launcher]: Starting browser PhantomJS
25 07 2017 14:07:44.415:INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket 3Lwn5pn5_bq63C9PAAAA with id 42841957
PhantomJS 2.1.1 (Linux 0.0.0) ERROR
  Error: Cannot find module "."
  at index.ts:15327

windows and macos passed..
my repo is this

typescript declaration error, vue has no default export

After updating from version 3.4 to 4.0 i am getting type script errors.

ERROR in node_modules\vue-class-component\lib\declarations.d.ts
(1,8): error TS1192: Module '"node_modules/vue/types/index"' has no default export.
ERROR in node_modules\vue-class-component\lib\index.d.ts
(1,8): error TS1192: Module 'node_modules/vue/types/index"' has no default export.
ERROR in node_modules\vue-property-decorator\lib\vue-property-decorator.d.ts
(1,8): error TS1192: Module '"node_modules/vue/types/index"' has no default export.

It seems you changed import of vue in 4.0 which is causing the issue:
from: import * as Vue from 'vue';
to: import Vue from 'vue';

my package versions:
"vue": "~2.2.1",
"typescript": "~2.2.1"

my tsconfig:
"compilerOptions": {
"module": "amd",
"target": "es5",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitOnError": false,
"lib": [
"es2016",
"dom"
],
"moduleResolution": "node",
"skipLibCheck": true
}

SSR

I use Nuxt and there is SSR, I try to use property-decorator with SSR but got a error:

My component:

import Vue from 'vue';
import { Component, Prop } from 'src/plugins/classComponent';

@Component()
class MainHeader extends Vue {
  @Prop({ type: String })
  title;
}

export default MainHeader;

error:

TypeError: Cannot redefine property: title
    at Object.defineProperty (<anonymous>)
    at defineProperty (~/core-js/library/fn/object/define-property.js:4:0)
    at _initDefineProp (0.server-bundle.js:316:32)
    at new MainHeader (0.server-bundle.js:371:207)
    at collectDataFromConstructor (D:\Projects\Vue\smart-landing\node_modules\vue-class-component\dist\vue-class-component.common.js:48:16)
    at VueComponent.data (D:\Projects\Vue\smart-landing\node_modules\vue-class-component\dist\vue-class-component.common.js:104:20)
    at getData (D:\Projects\Vue\smart-landing\node_modules\vue\dist\vue.runtime.common.js:2751:17)
    at initData (D:\Projects\Vue\smart-landing\node_modules\vue\dist\vue.runtime.common.js:2720:7)
    at initState (D:\Projects\Vue\smart-landing\node_modules\vue\dist\vue.runtime.common.js:2661:5)
    at VueComponent.Vue._init (D:\Projects\Vue\smart-landing\node_modules\vue\dist\vue.runtime.common.js:3752:5)

does not support 'functional' config?

If i use 'functional:true', there is a error :
Argument of type '{ functional: boolean; }' is not assignable to parameter of type 'VueClass'.
Object literal may only specify known properties, and 'functional' does not exist in type 'VueClass'.

my code is

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

@component({ functional: true })
class MyFunctionalComponent extends Vue {
render(h, ctx) {
let component = ...
....
return h(component, ctx.data, ctx.children)
}
}
`

Provide observed data

I need a little help. I would like to provide an observed property but it is not working as expected:

@Provide() get foo() { return this.bar; }
bar: string = "baz";

In my child component I have:

@Inject() foo: string;

The value "baz" is initially bound to foo correctly but foo is not reactive.

Note: this works using functions but this really isn't ideal.

@Provide() get foo() { return () => this.bar; }
@Inject() foo: () => string;

If it helps, I am attempting something similar to this example:

const Provider = {
  provide () {
    const foo = {}
    Object.defineProperty(foo, 'bar', {
       enumerable: true,
       get: () => this.bar,
    })
    return { foo }
  },
  data: () => ({ bar: 'baz' })
}

Problem with arrow function body inside @Prop()

This code gives me error message [ts] Property or signature expected at let acceptedValues = ...

  @Prop()
  activeColor: {
    type: String,
    default: 'success',
    validator: (value) => {
      let acceptedValues = ['primary', 'info', 'success', 'warning', 'danger'];
      return acceptedValues.indexOf(value) !== -1;
    }
  }

Parser, on the other hand, shows no errors with this code:

  @Prop({
    type: String,
    default: 'success',
    validator: (value) => {
      let acceptedValues = ['primary', 'info', 'success', 'warning', 'danger'];
      return acceptedValues.indexOf(value) !== -1;
    }
  })
  activeColor: string;

What is the right way to do this?
Thanks.

Can't get properties to work

I followed your example and created a Vue component that looks like this:

import Vue from 'vue'
import { Component, Inject, Model, Prop, Watch } from 'vue-property-decorator'

import { Report } from '../../classes/Report'

@Component
export class ReportCard extends Vue {
  @Prop()
  selected: boolean

  @Prop()
  report: Report

  isSelected: boolean = this.selected

  toggleSelectReport (): void {
    this.$emit('change', this.isSelected, this.report)
  }

  deleteReport (): void {
    this.$emit('delete', this.report)
  }

  openReport (): void {
    this.$emit('open', this.report)
  }
}

However, Vue is complaining that the property "report" was not defined:

Property or method "report" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.

How to use @Model along with a @Prop property

@Model('change') checked translates to:

{
  model: {
    prop: 'checked',
    event: 'change'
  }
}

But then you cannot use @prop() checked to define the property, since it is used already. What's the workaround for it?

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

@Component({})
export default class Hello extends Vue {
  @Prop() checked: string
  @Model('changed') checked: boolean
}

How bind this in a Prop decorator.

If the Prop decorator 'default' is a function. I want bind this to vm instance.How can I do this.

@Prop({
    default: () => {
      const years = new Array(11)
      const currentYear: number = currentDate.getFullYear()

      return map(years, (v, k) => ({
        name: `${currentYear - 6 + k}${this.t('vcs.yearAppand')}`, // this is not vm instance
        value: currentYear - 6 + k
      }))
    }
  })

@Prop() made type is any

i used like this:

@Prop()
propA: number

Expected behavior

props: {
    propA: Number
}

Actually behavior

i captured this at the vue-devtools
image

[proposal] make @prop more concise

Right now you have this code in the example:

@prop(Number)
propA: number;

@prop({
  type: String,
  default: 'default value'
})
propB: string;

However, this could be way way more concise I believe. I would like to propose the following:

Since we're using typescript, how about inferring the property-type from the type that's already defined for typescript? And to make it even better, we could also infer the default value from the type definition itself. So that would change the code into the following:

@prop propA: number;

@prop propB: string = "default value";

What do you think? I would really really like it to be this concise.

While we're at it, I would like to make one more proposition. Props also have a boolean-value for whether or not they are required of course. I would like that to be inferred as well. If no default value has been provided then I think it should be inferred that the prop is required. So in this case propA would be a required prop. And if someone really wants propA to not be required, but also not have a default value, then of course they could define it with null as the default value.

Let me know what you think.

(see here for inspiration)

Use with Babel

Does this library work with Babel?

It seems that @component works but others like @prop do not work and Vue complains:

TypeError: Cannot redefine property

Let me know & thanks in advance!

Please Tag Releases

I think it would be greatly appreciated, if you could tag your releases. That way it is easier to switch to a previous release in case something like #32 happens.

Thank you!

Babel 7 support?

It's known that vue-property-decorator's @Prop decorators don't work with Babel 6. Is there any chance this scenario changes with upcoming Babel 7 decorators implementation?

Different sources when using npm install

I followed install and usage procedures as described in you documentation.
Vue does not seem to be exported by your library.

When checking files imported by npm in node_modules, sources are different from the github ones.
Maybe you commited changes but did not change the version?

strictFunctionTypes

I wanted to enable strict in my tsconfig.json, but the option strictFunctionTypes option leads to errors in my components.
If the component is empty, it works fine, but as soon as I add any kind of attributes/methods, the compiler complains.

I'm quite familiar with TypeScript yet, so I'm not sure if I'm doing something wrong, if strict is not supported, or if it's just not possible.

Here's a basic component that exhibits the issue:

@Component
export default class Hello extends Vue {
  @Prop()
  test: boolean
}

Here's what the errors look like:

 error  in [...]/src/components/Hello.vue.ts

[tsl] ERROR in [...]/src/components/Hello.vue.ts(24,2)
      TS2345: Argument of type 'typeof Hello' is not assignable to parameter of type 'VueClass<Vue>'.
  Type 'typeof Hello' is not assignable to type 'new (...args: any[]) => Vue'.
    Type 'Hello' is not assignable to type 'Vue'.
      Types of property '$options' are incompatible.
        Type 'ComponentOptions<Hello, DefaultData<Hello>, DefaultMethods<Hello>, DefaultComputed, PropsDefiniti...' is not assignable to type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Rec...'.
          Type 'Hello' is not assignable to type 'Vue'.

 error  in ./src/router/index.ts

[tsl] ERROR in [...]/src/router/index.ts(8,27)
      TS2345: Argument of type '{ mode: "history"; routes: { path: string; name: string; component: typeof Hello; }[]; }' is not assignable to parameter of type 'RouterOptions | undefined'.
  Type '{ mode: "history"; routes: { path: string; name: string; component: typeof Hello; }[]; }' is not assignable to type 'RouterOptions'.
    Types of property 'routes' are incompatible.
      Type '{ path: string; name: string; component: typeof Hello; }[]' is not assignable to type 'RouteConfig[] | undefined'.
        Type '{ path: string; name: string; component: typeof Hello; }[]' is not assignable to type 'RouteConfig[]'.
          Type '{ path: string; name: string; component: typeof Hello; }' is not assignable to type 'RouteConfig'.
            Types of property 'component' are incompatible.
              Type 'typeof Hello' is not assignable to type 'VueConstructor<Vue> | ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultCompute...'.
                Type 'typeof Hello' is not assignable to type 'AsyncComponent<DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, Record<string, any>>'.
                  Type 'typeof Hello' provides no match for the signature '(resolve: (component: Component<DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, Record<string, any>>) => void, reject: (reason?: any) => void): void | Promise<VueConstructor<Vue> | FunctionalComponentOptions<Record<string, any>, PropsDefinition<Record<string, any>>> | ThisTypedComponentOptionsWithArrayProps<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, string> | ThisTypedComponentOptionsWithRecordProps<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, Record<string, any>> | EsModuleComponent>'.

Can you shed some light on this for me?

What about @Mixin?

Not quite sure how just yet, but it would be really nice to have an @Mixin. Something analagous to @Component. That way you could write something like:

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

import BarComponent from 'app/components/bar-component.vue';
import BazMixin from 'app/mixins/baz-mixin.ts';

@Mixin({
    components: {
        BarComponent
    }
    mixins: {
        BazMixin
    }
})
export default class FooMixin {
    @Prop() public propOne: string;
    public dataOne: string;
    public dataTwo: boolean;

    public created() {
        console.log("hooked into created in FooMixin");
    }

    public methodOne(): void {
        // do stuff
    }
}

What do you think?

tests broken

System

node: v8.9.0
npm: 5.5.1
os: Windows x64 1709
tsc: 2.6.1

Steps to reproduce:

npm i
npm run build
npm run build:umd
npm t 

Output

 6 failed

  @Emit decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:217


            child.resetCount();
   218:     t.is(result.called, true);

  Error thrown in test:

  TypeError {
    message: 'child.resetCount is not a function',
  }



  @Inject decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:269

   268:     var child = new Child({ parent: parent });
                   ild.foo, 'one');
                   ild.bar, 'two');

  Difference:

  - undefined
  + 'one'



  @Model decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:309

                               Test().$options;
   309:     t.deepEqual($options.model, { prop: 'checked', event: 'change' });


  Difference:

  - undefined
  + {
  +   event: 'change',
  +   prop: 'checked',
  + }



  @Prop decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:345

                                    rray)) {
                  deepEqual(props['propA'], { type: Number });
   346:         t.deepEqual(props['propB'], { type: String, default: 'propB' });

  Error thrown in test:

  TypeError {
    message: 'Cannot read property \'propA\' of undefined',
  }



  @Provide decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:397

   396:         var child = new Child({ parent: parent });
                   s(child.one, 'one');
                   s(child.two, 'two');

  Difference:

  - undefined
  + 'one'



  @Watch decorator test

  D:\Workspace\Home\vue-property-decorator\test\decorator.spec.js:536

                    ions = new Test().$options;
   536:     t.is($options.watch['expression'].handler, 'method');
   537:     t.is($options.watch['moreExpression'].immediate, true);

  Error thrown in test:

  TypeError {
    message: 'Cannot read property \'expression\' of undefined',
  }

@filter

It would be nice to have an @filter option to specify a filter, so they can easily be extended with a class.

Assigning data to props

This may end up being a dumb question, but I'm getting an error when using vue-property-decorator

"Property or method "currentCount" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option."

with the following:

counter.ts --

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

@Component
export default class CounterComponent extends Vue {

    @Prop() initialCount: number;
        
    //currentCount: number = 0; // this works
    // replace above with, doesn't work.
    // currentCount: number = this.initialCount;     
  
    incrementCounter() {
        this.currentCount++;
    }
}

counter.vue.html --

<template>
    <div>
        <h1>Counter</h1>

        <p>This is a simple example of a Vue.js component.</p>

        <p>Current count: <strong>{{ currentCount }}</strong></p>

        <button @click="incrementCounter">Increment</button>
    </div>
</template>

<script src="./counter.ts"></script>

any help appreciated..

@watch doesn't work in Firefox

I successfully compiled my project with TypeScript, but this line caused me some trouble:

(componentOptions.watch || (componentOptions.watch = {}) as any)[path] = {handler, deep, immediate}

In Firefox, every object has an implicit watch function (see here), which is a non-false value, so the default expression will never evaluate.

I fixed it with this workaround:

if (typeof componentOptions.watch !== 'object') {
  componentOptions.watch = {}
}
(componentOptions.watch as any)[path] = { handler, deep, immediate }

I am no expert in TypeScript/ES6, so there might be a better solution.

Error with vue 2.2+

I'm having the following issue, it might be related to the import changes with Vue in 2.2 ( https://vuejs.org/v2/guide/typescript.html#Important-2-2-Change-Notice-for-TS-webpack-2-users )

Specifically:

import Vue = require('vue') will now return a synthetic ES module object instead of Vue itself.

Uncaught TypeError: Right-hand side of 'instanceof' is not callable
    at Prop (vue-property-decorator.js:28)
    at DecorateProperty (Reflect.js:530)
    at Object.decorate (Reflect.js:100)
    at __decorate (ModalDetailsButtons.vue:14)
    at Object.<anonymous> (ModalDetailsButtons.vue:28)
    at __webpack_require__ (bootstrap 39ceb28…:686)
    at fn (bootstrap 39ceb28…:105)
    at Object.<anonymous> (ModalDetailsButtons.vue?af98:3)
    at __webpack_require__ (bootstrap 39ceb28…:686)
    at fn (bootstrap 39ceb28…:105)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.