40
votes

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??

6

6 Answers

76
votes

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>()
  };
},
17
votes

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: []
    };
  },
})
11
votes

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() : {
  people: Array<any>, // if possible, replace `any` with something more specific
} {
  return {
    players: []
  };
},

Tada! players is now type Array of any.

4
votes

I found another method that is more close to the typical syntax, while keeping the code short.

data() {
  return new class {
    players: Player[] = []
  }();
},
2
votes

Type assertion using the '<>' syntax is forbidden. Use the 'as' syntax instead.

It will look like this:

players: [] as Player[]
0
votes

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);
       });
    },
 });