TinyTiger
TinyTiger

Reputation: 2053

Problems with Vue 3.2 <script setup> tag and TypeScript types

I'm trying to use the Vue 3.2 <script setup> tag with TypeScript.

I have a simple use case where I want to display a user ID in the template.

My code is technically working. It displays the user ID just fine.

But there are two weird things...

  1. I have defined a user prop with a type of User that I imported from the Firebase SDK. This works, but I get an error on the User type that says: 'User' only refers to a type, but is being used as a value here. ts(2693). Why am I getting this error and how to fix it?

  2. The help docs say I do not need to import { defineProps } from "vue";. But if I don't do the import I get a 'defineProps' is not defined error. This is confusing. Why am I forced to import it when the docs say otherwise?

Here is my full code:

<template>
  <div>Logged in as {{ user.uid }}</div>
</template>

<script setup lang="ts">
import { defineProps } from "vue"; //Docs say this is not needed, but it throws an error without it
import { User } from "firebase/auth";

defineProps({
  user: {
    type: User, //ERROR: 'User' only refers to a type, but is being used as a value here. ts(2693)
    required: true,
  },
});
</script>

Upvotes: 11

Views: 16130

Answers (3)

Adam  M.
Adam M.

Reputation: 1193

I don't recommend setting up global read only variables in the .eslintrc, that is not correct and only hides a portion of the configuration issue you may be seeing.

So to begin with, you'll want Volar installed in VSCode and uninstall vetur, and you'll need to add the vue eslint parser to your project with the following command:

npm install --save-dev eslint vue-eslint-parser

and in your .eslintrc.js file which should be in the root of your project (vue-project/.eslintrc) you'll want to set your parser to vue-eslint-parser. a simple .eslintrc file for a vue ^3.2.6 project can look like this:

module.exports = {
    root: true,
    env: {
        node: true,
       'vue/setup-compiler-macros': true, 
    },    

    extends: [
        'plugin:vue/vue3-essential',
        'plugin:vue/vue3-recommended',
    ],
    parser: "vue-eslint-parser",
}

this isn't a minimum example or even complete for vue but a decent start to fixing this specific option and getting linting in your project. note that adding more to the extends array may alter the linting and break this again, namely 'eslint:recommended'. And for what its worth, I'm not so sure Vue's out-of-the-box linting situation they provide is actually perfect and it still needs some work.

I'd recommend some additional reading at the following links:

https://vuejs.org/guide/scaling-up/tooling.html#linting

https://github.com/vuejs/vue-eslint-parser

https://github.com/vuejs/core/issues/4994#issuecomment-1125677494

Upvotes: 1

Ihsan Fajar Ramadhan
Ihsan Fajar Ramadhan

Reputation: 1033

in script setup you can define props like this instead:

<template>
  <div>Logged in as {{ user.uid }}</div>
</template>

<script setup lang="ts">
import { defineProps } from "vue"; //Docs say this is not needed, but it throws an error without it
import { User } from "firebase/auth";

defineProps<{ user: User }>();
</script>

another solution is as @bassxzero suggested, you can use

defineProps<{ user: { type: Object as PropType<User>; required: true } }>()

without using withDefaults it will be automaticly required

EDIT: The answer below this line is outdated, it was based on this old docs. you should check the newer docs here.

also, about:

import { defineProps } from "vue"; //Docs say this is not needed, but it throws an error without it

you actually don't need to import it, but you need to define it inside .eslitrc.js

globals: {
    defineProps: 'readonly',
    defineEmits: 'readonly',
    defineExpose: 'readonly',
    withDefaults: 'readonly'
  }

Upvotes: 20

Yoannes Geissler
Yoannes Geissler

Reputation: 841

This solved the problem for me

.eslintrc.cjs

extends: [...],
env: {
  "vue/setup-compiler-macros": true,
},
rules: {...}

Upvotes: 3

Related Questions