vue-class-component + typescript: how to use a component's class as a type of "this" in imported function?

1.3k views Asked by At

I'm using vue-class-component and I have an imported function, which I want to use as a value of my component's method. To illustrate what i want to achive, let's say that I have a file TestComponent.vue, which looks like this:

<template>
  <div class="wrapper">
    <div class="text">{{ helper() }}</div>
  </div>
</template>

<script lang="ts">
  import { Component, Vue } from 'vue-property-decorator';
  import helper from './helper';

  @Component({
    name: 'TestComponent' 
  })
  export default class TestComponent extends Vue {
    someString = 'I want it to be shown';
    helper = helper;
  }
</script>

And my helper.ts file is like this:

export default function(this: any) {
  return `${ this.someString } [ this text was added in helper function ]`; 
} 

The problem is that i don't want to assign this in helper.ts to any type. I want it to be a type of TestComponent class. But when I type this:

import TestComponent from './TestComponent.vue';

export default function(this: TestComponent) {
  return `${ this.someString } [ this text was added in helper function ]`; 
} 

I have an error which says that "property 'someString' does not exist on type 'Vue'". I've found a solution. If i put a class definition to a separate file, let's say TestComponentClass.ts, then import it in TestComponent.vue and type export default class TestComponent extends TestComponentClass {}, I can also import this class in helper.ts and use it as a type of this keyword inside a function. But that seems too tedious.

So my questions are:

  1. Is there a better way to achive this?
  2. How @Component decorator actually affects class' type? I tried to search for an answer in official docs but it doesn't explain implementation of this decorator in depth.

Thanks in advance!

1

There are 1 answers

0
Igor Nikiforov On

You could potentially use a thing called mixin. The idea is that instead of writing

export default TestComponent extends Vue {}

you write separate class which extends Vue where you specify all additional properties you want and re-write your TestComponent as extending mixins and not Vue directly:

TestMixin.ts

import Component, { Vue } from 'vue-class-component'

@Component()
export default class TestMixin extends Vue {
  someString = 'Anything you want it to be';
}

TestComponent.vue

import Component, { mixins } from 'vue-class-component'
import TestMixin from './mixins/TestMixin';

@Component()
export default class TestComponent extends mixins(TestMixin) { ... }

That way the TestComponent would have your "someString" property.