Reputation: 10328
I'm currently using Vue.js with Typescript in a webpack project.
As indicated in the Recommended Configuration in my tsconfig.json
I have:
"strict": true,
Inside one of my component i have:
declare interface Player {
cod: string,
param: string
}
export default Vue.extend({
name: 'basecomponent',
data() {
return {
players: []
};
},
created()
let self = this
axios.get('fetch-data')
.then((response) => {
let res: Players[] = response.data;
for(let i = 0; i < res.length; i++){
self.players.push(res[i]);
}
})
.catch((error: string) => {
console.log(error);
});
},
});
but when I try to compile i get:
error TS2345: Argument of type 'Player' is not assignable to parameter of type 'never'.
Cause I believe players: []
has never[]
type.
My question is: how can I infer type Vue data object properties??
Upvotes: 85
Views: 102644
Reputation: 13719
To not resort to describing the whole data
structure, a more viable approach would probably be to first define players
as a variable with explicit type:
export default Vue.extend({
name: 'basecomponent',
data() {
const players: Player[] = [];
return {
players: players
};
},
...
This should work for other complex types as well, not just for arrays. Though I'm yet to find out how to tell volar not to narrow the union type by the initializer value -_-
Upvotes: 0
Reputation: 495
Your data
method has an undeclared return value.
If you supply one, TypeScript will know what to expect with players
.
You just need to expand the data() {
line.
e.g.:
data() {
return {
players: []
};
},
needs to become:
data() : {
players: Array<any>, // if possible, replace `any` with something more specific
} {
return {
players: []
};
},
Tada! players
is now of type Array
of any
.
Upvotes: 28
Reputation: 3747
In case anyone comes across this in the future, here is the answer that solved my problem. It is a little more "wordy", but it does the type inference properly everywhere within the Vue.extend()
component definition:
interface Player {
cod: string,
param: string
}
// Any properties that are set in the `data()` return object should go here.
interface Data {
players: Player[];
}
// Any methods that are set in the "methods()" should go here.
interface Methods {}
// Any properties that are set in the "computed()" should go here.
interface Computed {}
// Any component props should go here.
interface Props {}
export default Vue.extend<Data, Methods, Computed, Props>({
name: 'basecomponent',
data() {
return {
players: []
};
},
// You probably will want to change this to the "mounted()" component lifecycle, as there are weird things that happen when you change the data within a "created()" lifecycle.
created() {
// This is not necessary.
// let self = this
// If you type the Axios.get() method like this, then the .data property is automatically typed.
axios.get<Players[]>('fetch-data')
.then(({ data }) => {
// This is not necessary.
// let res: Players[] = response.data;
// for(let i = 0; i < data.length; i++){
// self.players.push(data[i]);
// }
this.players = data;
})
.catch((error: string) => {
console.log(error);
});
},
});
Upvotes: 5
Reputation: 5760
I found another method that is more close to the typical syntax, while keeping the code short.
data() {
return new class {
players: Player[] = []
}();
},
Upvotes: 13
Reputation: 9315
This should work:
declare interface Player {
cod: string,
param: string
}
declare interface BaseComponentData {
players: Player[]
}
export default Vue.extend({
name: 'basecomponent',
data(): BaseComponentData {
return {
players: []
};
},
})
Upvotes: 32
Reputation: 1915
To add to Joshua's answer, you may want to declare the type of players inline so your code doesn't get too verbose as your data gets larger.
data() {
return {
players: [] as Player[]
};
},
another option:
data() {
return {
players: new Array<Player>()
};
},
Upvotes: 142
Reputation: 105
Type assertion using the '<>' syntax is forbidden. Use the 'as' syntax instead.
It will look like this:
players: [] as Player[]
Upvotes: 8