Vue: Defining typed props interface including optional properties

I created a method that I want to be accessible on all my Vue instances, so I can use it in case of an error and display a specific error component. Similar to the functionality provided by vue-error-page. Since I am working with typescript, I now want to ensure that the component is called with the correct typed props, to receive compile time errors if there is any inconsistency in the passed props.

Currently, I have the following code in a shims.d.ts file:

import Vue, {VueConstructor} from 'vue'

declare module 'vue/types/vue' {
    interface Vue {
        $error (component:VueConstructor<Vue>, props:unknown) : void;
    }
}

This allows me to call my plugin like this. The object passed matches the props definition of the ErrorPage component:

import Vue from "vue";
import ErrorPage from "./views/ErrorPage.vue";
export default Vue.extend({
  mounted() {
    this.$error(ErrorPage, { errorTitle: "Could not load the page" });
  }
});

Although it works, I aim to receive a compile-time error when the props don't align with what the component expects.

To achieve this, I decided to modify the shims.d.ts as follows:

declare module 'vue/types/vue' {
    interface Vue {
        $error<Props> (component:ExtendedVue<Vue, unknown, unknown, unknown, Props>, props:Props) : void;
    }
}

Now, I encounter compile-time errors when the props object doesn't match. However, I also face errors when I do not provide optional properties. Here's how my ErrorPage component looks like:

import Vue from "vue";
export default Vue.extend({
  name: "Error",
  props: {
    errorTitle: {
      type: String,
      required: true,
      default: "Error"
    },
    errorDescription: {
      type: String,
      required: false,
      default:
        "Something went wrong."
    }
  }
});

If I omit passing errorDescription, I should not receive an error. That's my objective. I want to be able to perform the following actions:

// Should compile successfully.
this.$error(ErrorPage, {errorTitle: "Oops", errorDescription: "Something went wrong" });

// Should compile successfully but currently does not. Results in error message:
// Argument of type '{ errorTitle: string; }' is not assignable to parameter of type '{ errorTitle: string; errorDescription: string; }'.
// Property 'errorDescription' is missing in type '{ errorTitle: string; }' but required in type '{ errorTitle: string; errorDescription: string; }'."
this.$error(ErrorPage, {errorTitle: "Oops" });

TL;DR Question:

How can I make sure that my method call remains type-safe with props as an argument, while still allowing for optional properties to be omitted? I have the flexibility to modify both the shims.d.ts and the ErrorPage component.

Answer №1

Even if you mark it as optional, the typescript type remains String therefore it must be provided when invoking the function.

You can attempt this approach (no guarantee that it will work)

Create a nullable type with an alias

type ErrorDescriptionType = String | undefined | null

Then use this as the type for errorDescription

errorDescription: {
  type: Object as () => ErrorDescriptionType,
}

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

Angular 7's innovative method for handling singleton instances: Dynamic provider

In my Angular application, I have the ability to display lists of videos or articles along with their details. There are two main components: ContentListPage and ContentDetailsPage, which serve the same purpose for both videos and articles. The only diff ...

Warning: Node encountering unexpected Unhandled Promise Rejection ERROR

I've encountered a problem in my code that is triggering an UnhandledPromiseRejectionWarning in Node, but I'm struggling to understand the root cause. Here's a simplified version of the code: export class Hello { async good(): Promise<s ...

Ways to assign values to an array within an object

I'm attempting to transfer the contents of one array into an array within an object, but I keep encountering this error: Type 'any[]' is not assignable to type '[]'. Target allows only 0 element(s) but source may have more. Here ...

Is there a way to enable live-reload for a local npm package within a monorepo setup?

Currently, I am in the process of setting up a monorepo workspace that will house a Vue 3 application (using vite and TypeScript), cloud functions, and a shared library containing functions and TypeScript interfaces. I have successfully imported my local ...

Error in VueJS template: mustache brackets are attempting to render a prop that has not been defined

Just learning VueJS and looking for any guidance. Currently working on creating Bootstrap 4 navs with Vue. The code below is functioning well: var Tabs = new Vue({ el: '#tabs', components: { 'tab-view': TabView, }, ...

Sending a POST request to an API with Angular and passing an object as the payload

I'm currently working on adding a feature to my app where I can take the products from an order and send them to the cart, essentially replicating the entire order. While I have successfully retrieved the order, I am facing difficulty in sending it b ...

Having trouble with installing Vue CLI?

I am encountering issues while attempting to set up VueJS. I am currently utilizing Bash on Ubuntu on Windows node -v v15.12.0 npm -v 7.6.3 Initially, I attempted the following: npm install -g @vue/cli However, this resulted in various warnings and ...

Having difficulty maintaining trailing zeroes in decimals after converting to float in Angular

I need assistance with converting a string to float in Angular. Whenever I use parseFloat, it seems to remove the zeros from the decimal values. How can I ensure that these zeros are retained with the numerical values? The example below should provide more ...

Guide to implementing dynamic conditional rendering in Vue.js loops (utilizing v-if within v-for)

I am currently working on a table component in a .vue file where I want to display icons based on the direction of the order clicked. For example: <th v-for="(column, index) in columns" :key="index" @click="sort( index )"> <span& ...

Is it possible to initially design a login page using HTML/CSS and JavaScript, and then integrate VUE into it?

As part of a school project, I am tasked with developing a web-based application for a library system. The goal is to create a platform where librarians can login and manage books by adding, removing, or editing them. My responsibility lies in handling the ...

I am in need of some guidance - where can I locate the documentation for vue cli

Searching for specific build modes tailored to my Vue CLI 2 application has proven to be a challenge. Despite consulting various resources, all the information I come across pertains to Vue CLI 3. After attempting to locate documentation for Vue CLI 2, u ...

Calculating the sum of values in a JSON array using a specific parameter in Typescript

A flat JSON array contains repetitive identifier, categoryId, and category: data: [ { "identifier": "data", "categoryId": "1", "category": "Baked goods", "product": "Aunt Hattie's", "price": "375" } ...

After successfully building with Vite, an error occurs stating "TypeError: can't convert undefined to object." However, during development with Vite, everything functions flawlessly

Currently, I am utilizing Vite in conjunction with React and Typescript for my project. Interestingly, when I execute 'vite dev', the live version of the website works flawlessly without any errors showing up on the console. However, things take ...

The file import is restricted based on the user's input

I am facing an issue with my small vue.js app. My goal is to import a specific json file based on user input. import content from "@/posts/posts/" + new URL(location.href).searchParams.get('id') + ".json"; Every time I attem ...

Best approach for managing Union Types in Angular 16 Templates / Utilizing Type Inference?

Currently, I'm immersed in a project using Angular 16 where my focus lies on applying a reactive declarative method. Oftentimes, I find myself working with Observables that emit varying data types - either successful data or an error object. Each ret ...

Integrating Constant Contact API into a Next.js application

I'm trying to integrate the Constant Contact API into my Next.js application. I've looked through the documentation, but it only provides examples for PHP and Java. How can I effectively use the authentication flow and create an app on the dashbo ...

When using Router.push() in next.js, the error TypeError: products.map is not a function may arise

Currently, I am implementing redux saga in my project. Here is how the state looks: const productList = useSelector((state: RootState) => state.productList); const { loading, error, products, page, pages } = productList; In the useEffect hook, I dispa ...

Send information as FormData object

I'm getting the data in this format: pert_submit: {systemId: "53183", pert-id: "176061", score: 0, q2c: "3\0", q2t: "", …} Now I need to send it as FormData in my post request. Since I can't use an ...

What is the resolution if I need to utilize a property that is untyped?

Transitioning to TypeScript from plain old JavaScript is a step I'm taking because I believe it offers significant advantages. However, one drawback that has come to light is that not all attributes are typed, as I recently discovered. For instance: ...

Integration of Mocha with WebStorm

WebStorm offers a useful feature that adds a small arrow next to describe() and it() keywords when writing tests with Mocha, allowing for easy manual execution. However, there is a challenge: I require additional setup before each test, leading me to use ...