How to handle type errors when using properties in Vue3 Single File Components with TypeScript

I've hit a roadblock while attempting to utilize properties in Vue3. Despite trying various methods, I keep facing issues during the type-check phase (e.g.: yarn build).

The project I'm working on is a fresh Vue3-ts project created using Vite. Below is an example of my component:

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: "Test",
  props: {
    label: {
      type: String as PropType<string>,
      required: true,
    },
  },
  methods:  {
    onClick() {
      console.log(this.label);  // This line triggers an error!
    },
  },
});
</script>

I receive an error stating that this.label does not exist:

Property 'label' does not exist on type 'CreateComponentPublicInstance<Readonly<ExtractPropTypes<Readonly<ComponentPropsOptions<Data>>>> & ...

(volar raises a similar issue).

I've experimented with different approaches but haven't had any success, including:


Utilizing the <script setup> method to define props:

<script setup lang="ts">
const props = defineProps({
  classes: String,
  label: String,
})
</script>

This also gives a warning about the unused props variable. Although this isn't major, the initial error persists.


Implementing a setup method within my component:

  setup(props) {

    defineProps({
      classes: String,
      label: String,
    })
  },

Adopting the traditional way of defining props with overzealous type declarations:

export default defineComponent({
  name: "AppStory",
  props: {
    label: {
      type: String as PropType<string>,
      required: true,
    },
  },

A more conservative approach with type definitions:

export default defineComponent({
  name: "AppStory",
  props: {
    label: {
      type: String,
      required: true,
    },
  },

Does anyone have a successfully functioning Single File Component (SFC) in Vue3 that effectively utilizes properties? What am I missing here? Most examples I come across either lack props or don't incorporate TypeScript. The documentation for Vue3 doesn't focus much on TypeScript, and the examples provided do not seem to address this rather fundamental scenario.

Answer №1

I recently set up a new vite application using the vue-ts configuration, and I noticed that in the initial example, the only thing missing is the import of the `PropType` type.

<template>
  <div>
    <button @click="onClick">{{ label }}</button>
  </div>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue";

export default defineComponent({
  name: "Test",
  props: {
    label: {
      type: String as PropType<string>,
      required: true,
    },
  },
  methods: {
    onClick() {
      console.log(this.label); // This line yields an error!
    },
  },
});
</script>

Here is the parent component (default App.vue component)

<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld label="Hello Vue 3 + TypeScript + Vite" />
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Everything seems to be working well for me.

Now, let's take a look at the same example using the 'setup' keyword in the script tag:

<template>
  <div>
    <button @click="onClick">{{ label }}</button>
  </div>
</template>

<script lang="ts" setup>
import { PropType } from "vue";
const props = defineProps({
  label: {
    type: String as PropType<string>,
    required: true,
  },
});

const onClick = () => {
  console.log(props.label); // This line yields an error!
};
</script>

This setup also works without any issues.

Lastly, let's see how it looks when using the 'setup' method:

<template>
  <div>
    <button @click="onClick">{{ label }}</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from "vue";

export default defineComponent({
  name: "Test",
  props: {
    label: {
      type: String as PropType<string>,
      required: true,
    },
  },
  setup(props) {
    const onClick = () => {
      console.log(props.label); // This line yields an error!
    };
    return { onClick };
  },
});
</script>

Hoping this information helps resolve your issue.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Extending Interfaces Using Keys from an Array in Typescript

When dealing with a scenario where you want a pointfree omit, you can achieve this: type PlainObject<T> = {[key: string]: T} const omit = <K extends string>( name: K ) => <T, U extends PlainObject<T> & { [P in K]: T }>( ...

Tips for preventing repetition of code in multiple entry points in Rollup

My goal is to use rollup to process a group of input files and generate multiple output files in the dist directory that all have some common code shared between them. Below is my current rollup configuration: import path from 'path'; import pat ...

Vue: Exploring the Restriction of Using refs in Component Templates

I can't seem to figure out Vue refs. Whenever I define them in my main Vue instance's template, they work perfectly fine. However, when I define them within a component template, they don't seem to work at all. What could be causing this iss ...

Vue.js - computed property not rendering in repeated list

It seems like the issue lies in the timing rather than being related to asynchronous operations. I'm currently iterating through an object and displaying a list of items. One of the values requires calculation using a method. While the direct values ...

How can I save the content from a tiptap editor in a PHP form?

I'm looking to integrate the TipTap editor into a PHP form as a textarea field. I've set up a Vue component and passed it to the blade view. Blade view: <form method="post" action="{{ route('dashboard.edit.postInfo', ...

Tips for displaying dynamic content in VueJS?

I'm currently working on an app that allows users to choose which type of vuetify element they want to display on the page. There are 4 options available for selection. My goal is to render the corresponding vuetify component when a user clicks on the ...

Retrieving the location.host parameter within NgModule

I am currently working on integrating Angular Adal for authenticating my application's admin interface with Azure AD. However, I have encountered a challenge with the redirectUri setting. My goal is to dynamically retrieve the current app's host ...

How can I use a Vue.js function to extract latitude and longitude data from a nested JSON file?

When using getcoords(), I am only getting the first latitude and longitude for all entries in my array. However, when using the normal syntax {{fire.latitude}},{{fire.longitude}}, I am able to retrieve all latitudes and longitudes. I'm not sure why t ...

Ways to efficiently incorporate data into App.vue from the constructor

My app initialization uses main.js in the following way, import App from './App.vue'; const store = { items: [{ todo: 'Clean Apartment.', },{ todo: 'Mow the lawn!', },{ todo: 'Pick up ...

Can a webpage created with ASP.Net Core be encapsulated with Cordova?

My ASP.Net Core application utilizes server-side processing, particularly for cookie authentication, along with some Vue.js for added interaction. Can I package this code into mobile apps using Cordova, or will I need to refactor it to utilize XHR and JWT ...

What is the best way to find the correct static resource path in a production environment while utilizing Vite?

My image resources will show in the production environment like this when stored in the public folder: https://ip/static/img/xxx.png However, I want them to appear like this: https://ip/xxx/xxx/xxx/static/img/xxx.png, This is because: https://ip/xxx/xxx/ ...

Combine two arrays of data sources

mergeThreads() { const userId = this.auth.getUser().uid; const buyerThreads$ = this.afs.collection('threads', ref => ref.where('buyerId', '==', userId)).valueChanges(); const sellerThreads$ = this.afs.collection ...

Set a timeout for a single asynchronous request

Is there a way to implement a setTimeout for only one asynchronous call? I need to set a timeout before calling the GetData function from the dataservice, but it should be specific to only one asynchronous call. Any suggestions? Thank you. #html code < ...

Vue element fails to appear on the screen

As a newcomer to Vue.js and web development in general, I decided to dive into the vuejs guide. Something puzzled me - when creating a vue component using Vue.component(NameOfComponent, {...}) and inserting it into my HTML as <NameOfComponent></ ...

Definition of TypeScript array properties

Having some trouble creating a type for an array with properties. Can't seem to figure out how to add typings to it, wondering if it's even possible. // Scale of font weights const fontWeights: FontWeights = [300, 400, 500]; // Font weight alia ...

Can a npm package be created using only typescript?

I am working on a project that is specifically tailored for use with TypeScript projects, and I want the code inspection to lead to the actual lines of TypeScript code instead of a definition file. However, I am struggling to set up an npm project to achi ...

Tips for retrieving the state value and using it as a parameter in methods

Is there a way to utilize Vuex state and access it in the methods property of components? I have a state called "currentThreadId" that I would like to use within my methods. The issue I am facing is being able to retrieve the "currentThreadId" from the Vu ...

Issue with Vue JS: running the build command `npm run build` fails to generate the `index.html` file

While executing the command npm run build, I am facing an issue where it does not generate the index.html file in the dist/ directory. The purpose behind needing this index.html file is to deploy my Vue project on AWS EC2 at location (/var/www/html/). Can ...

Transmit information from an IONIC 3 application to a PHP server using the POST method

Having trouble sending data from Ionic 3 to php via the http library using post? When php tries to retrieve it, it's unable to locate. Below is the Typescript file that generates the token to be sent to php and calls the php file on localhost (xampp) ...

How can I access a file uploaded using dxFileUploader?

I am facing an issue with retrieving a file from dxFileUploader (DevExpress) and not being able to read it in the code behind. The file is only appearing as an object. Here is My FileUploader : { location: "before", ...