vue.js - Hvordan opprettholde korrekt TypeScript-type på Vue-komponentdata?
Jeg jobber med et Vue-prosjekt som jeg oppdaterer til Vue 3 med TypeScript. Jeg har funnet en merkelig oppførsel med TypeScript-parsere/kompilatoren. Jeg har følgende komponent:
export default defineComponent({
name: 'Test',
data() {
return {
test: new Child(),
};
},
methods: {
testMethod: function () {
this.test = new Child();
let test2 = new Child();
}
},
});
class Child {
b = 0;
}
I metoden tror parseren at test2 er av typen Child. Men den tror at this.test er av typen {b: number} (dvs. den har mistet forbindelsen til Child). Å holde musepekeren over datastrukturen (vscode) viser at når den opprettes der, tror den at typen er Child.
I dette eksemplet er det egentlig ikke et problem fordi det enkelt kan kaste det. Men hvis Child i stedet er definert som:
class Parent {
private a = 1;
}
class Child extends Parent {
b = 0;
}
da har this.test fortsatt samme type {b:number} (det mister det private medlemmet) og kan ikke lenger kastes til Parent. Dette fører til endeløs typecasting til any for å omgå problemet. Et annet symptom på at den ikke henter riktig type, er at noe som this.test.a=3 genererer property does not exist (ts2339), mens test2.a=3; genererer property is private and only accessible with parent (ts2341) (som er den riktige feilen).
Jeg har også prøvd å spesifisere returtypen til data() manuelt, med samme resultat.
Gjør jeg noe galt? Er dette bare hvordan Vue-pluginen fungerer med Typescript?
Svar #1
Som beskrevet her, er problemet at data-elementene er reaktive, og i innpakningen/utpakking mister klassen.
Løsningen der indikerer at det er anbefalt å bruke en shallowRef() (fordi det generelt er foretrukket å holde instansen rå for noe så komplekst):
export default defineComponent({
name: 'Test',
setup() {
return {
test: shallowRef(new Child()),
};
},
...
});
Hvis du ikke har noe imot (eller foretrekker) wrapperen, vil det å bare endre data til setup løse skriveproblemet:
export default defineComponent({
name: 'Test',
setup() {
return {
test: new Child(),
};
},
...
});
