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...
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?
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>
type: Object as PropType<User>,
make sure to import PropType
from vue This solved the problem for me
.eslintrc.cjs
extends: [...],
env: {
"vue/setup-compiler-macros": true,
},
rules: {...}
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,
},
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
.eslintrc
example don't cover the whole setup
API, so it misses important build-time variables, and that answer also breaks linting in regular <script>
tag, where the build-time variable will be actually undefined and never imported. So overall the answer solved the problem but missed nuance that could break builds, linting rules for commits, etc, etc. 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'
}
.eslitrc.js
globals didn't fully fix the problem. It stopped VScode from reporting it in the "problems" tab but TypeScript is still showing error 'defineProps' is not defined
when I save the file. Do I also need to update tsconfig.json with something to make it work? script setup
vue-eslint-parser
. If you what it done more correct please reference my answer.