I am trying to have typescript support on my Nuxt project.
I understood that I have to use Vue.extend when returning the component data like so:
import Vue from 'vue';
type Data = {
a: number
}
export default Vue.extend({
data():Data{
const a = 3;
return {
a
}
}
})
However if my component have injected properties, it does not attach those properties to this type.
import Vue from 'vue';
type Data = {
a: number
}
export default Vue.extend({
inject: ['b'],
data():Data{
const a = 3;
const c = this.b
^^^^
// ~~ Property 'b' does not exist on type 'Readonly<Record<never,any>> & Vue'
return {
a
},
methods:{
my_method(){
this.a // no problem here
this.b // Error here
}
}
}
})
Shouldn't infer also the injected type?
I am forced to use:
const that = this as any;
that I would like to avoid.
You can try to explicitly type this inside data method
import Vue from 'vue';
type Data = {
a: number
}
export default Vue.extend({
inject: ['b'],
data(this: { b: string }): Data {
const a = 3;
const c = this.b
return {
a
}
},
methods: {
my_method() {
this.a // no problem here
this.b // ok
}
}
})
Playground
You can take a look on Vue.extends type definition:
export interface VueConstructor<V extends Vue = Vue> {
new <Data = object, Methods = object, Computed = object, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): CombinedVueInstance<V, Data, Methods, Computed, Record<PropNames, any>>;
// ideally, the return type should just contain Props, not Record<keyof Props, any>. But TS requires to have Base constructors with the same return type.
new <Data = object, Methods = object, Computed = object, Props = object>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Record<keyof Props, any>>;
new (options?: ComponentOptions<V>): CombinedVueInstance<V, object, object, object, Record<keyof object, any>>;
// we are interested in first
extend<Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;
// ......
extend<Data, Methods, Computed, Props>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;
extend<PropNames extends string = never>(definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
extend<Props>(definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>;
extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>;
}
Hence, you can provide explicit generics:
export default Vue.extend<Data, { my_method: () => void }, object, 'b'>({
inject: ['b'],
data(): Data {
const a = 3;
const c = this.b
return {
a
}
},
methods: {
my_method() {
this.a // no problem here
this.b // ok
}
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With