I'm trying to convert my Vue 3 single page component scripts to use TypeScript.
When I create a brand new Test.vue
component that looks like this, I get no TypeScript errors my Visual Studio Code editor:
<script lang="ts">
import { defineComponent, inject, ref } from "vue";
export default defineComponent({
//Some code here
});
</script>
This is as expected because my code conforms to the Vue 3 TypeScipt docs.
But when I convert my other existing ExternalApi.vue
component to the same thing I am seeing errors on defineComponent
, inject
, and ref
:
Module '"vue"' has no exported member 'XXXX'. Did you mean to use 'import XXXX from "vue"' instead?
So why does a brand new Test.vue
component work but not the edited ExternalApi.vue
component?
Here is the full ExternalApi.vue
component I am trying to convert to TypeScript:
<template>
<div>
<div class="mb-5">
<h1>External API</h1>
<p>
Call Fauna.
</p>
<button class="btn btn-primary m-5" @click.prevent="callApi">
Call API
</button>
<label for="product-name">Product Name:</label>
<input
type="text"
v-model="productValue"
id="product-name"
name="product-name"
/><br /><br />
<button class="btn btn-primary m-5" @click.prevent="createProduct">
Create Product
</button>
</div>
<div class="result-block-container">
<div :class="['result-block', executed ? 'show' : '']">
<h6 class="muted">Result</h6>
{{ JSON.stringify(apiMessage, null, 2) }}
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, inject, ref } from "vue";
import { query as q, Client } from "faunadb";
export default defineComponent({
name: "Api",
setup() {
let productValue = ref("");
let apiMessage = ref(null);
let executed = ref(false);
const auth = inject("Auth");
const callApi = async () => {
const accessToken = await auth.getTokenSilently();
try {
const client = new Client({
secret: accessToken,
domain: "db.us.fauna.com",
port: 443,
scheme: "https",
});
const { Paginate, Documents, Collection } = q;
const data = await client.query(
Paginate(Documents(Collection("products")))
);
console.log(accessToken);
console.log(data);
apiMessage.value = data;
executed.value = true;
} catch (e) {
console.log(e);
apiMessage = `Error: the server responded with '${e.response.status}: ${e.response.statusText}'`;
}
};
const createProduct = async () => {
const accessToken = await auth.getTokenSilently();
try {
const client = new Client({
secret: accessToken,
domain: "db.us.fauna.com",
port: 443,
scheme: "https",
});
const { Create, Collection, CurrentIdentity } = q;
const data = await client.query(
Create(Collection("products"), {
data: {
name: productValue.value,
owner: CurrentIdentity(),
},
})
);
console.log("productValue data", data);
} catch (e) {
console.log(e);
apiMessage = `Error: the server responded with '${e.response.status}: ${e.response.statusText}'`;
}
};
return {
callApi,
createProduct,
apiMessage,
executed,
productValue,
};
},
});
</script>
On top of that, when compiling via npm run serve
the terminal throws the same errors for both Test.vue
and ExternalApi.vue
.
But it should not be showing errors at all because both of them conform to the Vue docs.
So what is going on here?
UPDATE:
This is what my shims-vue.d.ts
file contains. I'm not actually sure what this file does, but it was in the cloned repo:
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
And this is my package.json
file:
{
"name": "replicator",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 3000",
"build": "vue-cli-service build"
},
"dependencies": {
"@auth0/auth0-spa-js": "^1.13.6",
"@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/vue-fontawesome": "3.0.0-3",
"ansi-html": "^0.0.7",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-plus": "^1.0.2-beta.28",
"faunadb": "^4.4.1",
"glob-parent": "^6.0.2",
"set-value": "^4.1.0",
"vue": "^3.2.20",
"vue-router": "^4.0.11",
"vue-template-compiler": "^2.6.14",
"vuex": "^4.0.0-0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.13",
"@vue/cli-plugin-router": "4.5.13",
"@vue/cli-plugin-typescript": "^4.5.13",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "^4.5.13",
"@vue/compiler-sfc": "^3.0.0",
"sass": "^1.32.7",
"sass-loader": "7.3.1",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"typescript": "~3.9.3",
"vue-cli-plugin-element-plus": "~0.0.13"
}
}
CodePudding user response:
This error can appear if you're trying to use the Vue 3 composition API, but you have Vue 2 installed. Currently if you run npm install vue
you'll get version 2; you need to run npm install vue@next
to get version 3.
If you want to use version 2, the basic TypeScript approach for component definition is instead like this:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
// type inference enabled
})
</script>
I recommend trying vue-class-component and vue-property-decorator if you want to use TypeScript with Vue 2, they're really great!
CodePudding user response:
I was able to fix these import errors by upgrading TypeScript from 3.9.3 to 4.4.4: npm install typescript@latest
It seems that Vue 3.2.0 and above makes use of TS features in its declaration files that require an upgraded TypeScript. This release ships TypeScript typings that rely on Template Literal Types and requires TS >= 4.1.
Why did question asker run into this problem in their forked repo, but not the original one? This is because the original repo required vue ^3.0.0
, but TypeScript ~3.9.3
.
Normally yarn.lock
would ensure the same specific versions were installed, but when they switched from yarn
to npm
, the lockfile was regenerated, causing a version conflict when vue was upgraded but not typescript.
This problem is a good example of the importance of lockfiles!