Plastic
Plastic

Reputation: 10328

Set data Type in Vue data object with Typescript

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

Answers (7)

Klesun
Klesun

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

Joshua Hansen
Joshua Hansen

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

th3n3wguy
th3n3wguy

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

Ahmad
Ahmad

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

Ore4444
Ore4444

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

Michael Wilson
Michael Wilson

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

Related Questions