vue-class-component: Can't use @Component on TypeScript abstract component class
I wrote an abstract common class that extends Vue where I want to put some common logic, including some hook methods like created()
, but those methods are not invoked by the framework.
Here’s the abstract class implementing created()
.
abstract class DataEditorVue<T extends AbstractData> extends Vue {
creation: boolean = false;
data: T = null;
created() {
if (!this.data) {
this.data = this.buildDataInstance();
}
}
abstract buildDataInstance(): T;
abstract getApiResource(): AbstractDataResource<T>;
abstract getRouterPath(data: T): string;
abstract getRouterPathAfterDeletion(data: T): string;
remove() {
return this.getApiResource().deleteFromObject(this.data).then(() => {
return this.$router.push(this.getRouterPathAfterDeletion(this.data));
});
}
create() {
return this.getApiResource().create(this.data).then((data) => {
return this.$router.push(this.getRouterPath(data), () => {
this.creation = false;
this.data = data;
});
});
}
update() {
return this.getApiResource().update(this.data);
}
}
Here the concrete class, extending abstract one.
@WithRender
@Component({
components: {EditorControls}
})
class ObservationMilieuVue extends DataEditorVue<ObservationMilieu> {
@Inject('observationTaxonResource')
dataResource: ObservationTaxonResource;
buildDataInstance(): ObservationMilieu {
let data = new ObservationMilieu();
data.localisation = {id: this.$route.params.localisationId};
return data;
}
getApiResource(): ObservationTaxonResource {
return this.dataResource;
}
getRouterPath(data: ObservationMilieu): string {
return `/localisation/${data.localisation.id}/observation-milieu/${data.id}`;
}
getRouterPathAfterDeletion(data: ObservationMilieu): string {
return `/localisation/${data.localisation.id}`;
}
};
My actual workaround is to add a created()
method in concrete class to invoke super.created()
manually.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 22 (6 by maintainers)
That’s interesting. I did actually get abstract class mixins working fine and with type safety. Just had to hack around a bit with TypeScript. Not sure how stable this implementation is, but so far it seems to work fine.
Borrowing @lazarljubenovic example:
then this will have compile error on the SomeForm class name until you implement the required abstract method:
Non-abstract class 'SomeForm' does not implement inherited abstract member 'hasUnsavedChanges' from class 'DiscardableFormMixin'
Amazing! Thanks a lot @ReinisV ❤️Not sure how “stable” it is either, but it is indeed working as expected, and sounds like a well contained hack!
Seems like you simply forgot a
@ts-ignore
before the second@Component
. Here is a fully functional example, enhanced for projects using eslint, in an exampleLogin.ts
file:And the implementation in an actual component, showcasing option merging to override the Prop default value:
If I understand this thread correctly, it is not possible to use an abstract class on a mixin.
My use-case is that my mixin expects the component it’s used on implements a method. I am not sure how can I make this typesafe. What I’d love to do is this:
So, when I use this mixin on a component, that component needs to tell the mixin what it means that there are some unsaved changes. Currently I’m unable to do this.
What I tried doing was declaring an interface which the same name, which means that TS will merge the class and interface declaration into one:
This allows me to use
this.hasUnsavedChanges
in the mixin, but when I use the mixin on a class, there is no error if I don’t specify thehasUnsavedChanges
function.I need a behavior where this produces an error, telling me that I have to provide an implementation for the
hasUnsavedChanges
method.What I realize I can do is declare the interface with a different name.
Then, when using the mixin:
The problem with this approach is (apart from having to re-define the type of
this
in the mixin, but that’s boilerplate I’m fine with) that I’m responsible for remembering to write the implements part. It should be an implicit thing.To be clear, an
abstract
Mixin isn’t working?Typed mixins are too useful for me to have to manually set up for each project, so I bit the bullet and extracted the code here into a module.
https://www.npmjs.com/package/vue-mixin-decorator
The last comment on this vue forum thread seems to have the current best answer; and it uses mixins -
https://forum.vuejs.org/t/how-can-i-use-mixin-with-vue-class-component-and-typescript/21254/8?u=chriszrc
@304NotModified you also can use mixin in this project .
and use by this
the idea is copy from @HerringtonDarkholme 's av-ts . thanks him !
I see ! Thanks for help, i’ll have a look to mixins.