Reputation: 1057
In Vue, we have this type:
Vue.$refs: {
[key: string]: Vue | Element | Vue[] | Element[];
}
I have a third-party library (vuelidate) that adds a $v
property to everything Vue. It does not define types, so I'm doing it myself.
declare module 'vue/types/vue' {
interface Vue {
$v: any
}
interface Element {
$v: any
}
}
When I try to use $v
on $refs like so, typescript complains:
this.$refs.form.$v
Results in
Property '$v' does not exist on type 'Vue[]'.
That makes sense to me. What doesn't make sense, though, is how to add a property to Vue[]
and Element[]
so that this code compiles.
I've poured over the documentation, Stack Overflow, you name it, and I can't find a solution to this. How do I add a type to a specific array?
I understand why this doesn't work:
interface Vue[] {
$v: any
}
But I have no idea what to do to fix it.
Upvotes: 0
Views: 128
Reputation: 30879
Casting works, but I appreciate your desire to declare types so you don't have to cast every time. Vue[]
is actually shorthand for Array<Vue>
, a parameterization of the built-in generic interface Array
. You can add properties to Array
, but then they will be declared on arrays of all types, not just Vue[]
. You can mitigate this a bit with a conditional type, like so:
// Wrap with `declare global { ... }` if the file is an ES6 module
interface Array<T> {
$v: T extends Vue | Element ? any : unknown;
}
But truly, you don't want $v
on every Vue[]
, but only on Vue.$refs
. Unfortunately, given the way Vue.$refs
is declared, I don't believe there's any way to make this change via augmentation. You'd have to add a modified version of the vue
package to your project and change the declaration to read:
export interface Vue {
// ...
readonly $refs: { [key: string]: (Vue | Element | Vue[] | Element[]) & {$v: any} };
// ...
}
Obviously, this change would not be appropriate to send upstream. But you could send a PR to add a hook that other packages such as vuelidate
would then be able to augment:
// In vue/types/vue.d.ts:
export interface RefExtra {}
export interface Vue {
// ...
readonly $refs: { [key: string]: (Vue | Element | Vue[] | Element[]) & RefExtra };
// ...
}
// In vuelidate typings (or your project for now):
declare module 'vue/types/vue' {
interface RefExtra {
$v: any
}
}
Upvotes: 1