What is the proper way to enhance properties?

In the process of developing a Vue3 app using Typescript, one of the components is designed to receive data through props. Initially, everything functioned smoothly with the basic setup:

   props: {
     when: String,
     data: Object
   },

However, I decided to enhance the props by incorporating default values, validators, and more:

  props: {
    when: {
      type: String,
      default: '',
      validator(value: string) {
        return ['today', 'tomorrow', 'later'].includes(value)
      },
      required: true
    },
    data: {
      type: Object,
      default() {
        return {}
      },
      required: true
    },
  },

Subsequently, TypeScript started flagging issues within the setup() function that are puzzling to me:


TS2345: Argument of type '"data"' is not assignable to parameter of type 'string & ((number | unique symbol | "length" | "toString" | "toLocaleString" | "concat" | "join" | "slice" | "indexOf" | "lastIndexOf" | "every" | "some" | "forEach" | "map" | ... 29 more ... | ((searchElement: never, fromIndex?: number | undefined) => boolean)) & string)'.

pertaining to the line:

let allEvents = toRef(props, 'data')

TS2339: Property 'when' does not exist on type 'Readonly<LooseRequired<Readonly<readonly unknown[] & { [x: number]: string; } & { [iterator]?: IterableIterator<string> | undefined; length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; ... 17 more ...; includes?: ((searchElement: string, fromIndex?: number | undefined) =>...'.

related to the code:

  if (props.when === 'today') {
    // ...
  }

There are additional errors, but resolving them seems feasible once I identify the root cause.

Answer №1

There is a similarity in the issue at hand with another question where only the validator property was a regular function as discussed on Stack Overflow. In this case, both validator and default are regular functions (in different props), causing a breakdown in type inference for the props argument within setup(). I'm currently exploring the root problem through an open discussion on Stack Overflow.

An intriguing finding from your code snippet reveals a peculiar type representation for the props argument within setup(), resembling an intersection of keys of type string:

(parameter) props: Readonly<LooseRequired<Readonly<readonly unknown[] & {
    [x: number]: string;
} & {
    [Symbol.iterator]?: IterableIterator<string> | undefined;
    length?: number | undefined;
    toString?: string | undefined;
    toLocaleString?: string | undefined;
    ... 19 more ...;
    flat?: unknown[] | undefined;
}> | Readonly<...>>>

Solution

A workaround has been identified - replacing regular functions with arrow functions (where functions are required) in all props declarations:

export default defineComponent({
  props: {
    when: {
      type: String,
      default: '',

      //validator(value: string) {
      //  return ['today', 'tomorrow', 'later'].includes(value)
      //},
      validator: (value: string) => ['today', 'tomorrow', 'later'].includes(value), // ✅

      required: true
    },
    data: {
      type: Object,

      //default() {
      //  return {}
      //},
      default: () => ({}), // ✅

      required: true
    },
  },
})

This change results in a more structured type representation for the props argument:

(parameter) props: Readonly<LooseRequired<Readonly<{
    msg?: unknown;
    when?: unknown;
    data?: unknown;
} & {
    when: string;
    data: Record<string, any>;
} & {
    msg?: string | undefined;
}>>>

For demonstration purposes, check out the GitHub demo.

Answer №2

It is recommended that the validator be implemented as an arrow function:

when: {
  type: String,
  default: '',
  validator:(value:string)=>(['today', 'tomorrow', 'later'].includes(value)),
  required:true
 },
 

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

Integrate Tailwind CSS into the bundled JavaScript file

Is there a way to integrate tailwind css into bundle js effectively? Take a look at this example involving vue 3 and tailwind 3 https://github.com/musashiM82/vue-webpack. Upon executing npm run build , it generates 3 files: app.js ABOUTPAGE.js app.6cba1 ...

Enhancing external TypeScript modules

Currently, I am delving into the realm of enhancing external modules in TypeScript. I am diligently studying the official documentation and the DefinitelyTyped guides, poring over examples, and so forth. At this point, my goal is to incorporate custom prop ...

What is the best way to restrict navigation for a subroute in Vue.js?

One of the great things about beforeRouteLeave is its ability to prevent navigation under specific conditions. In my setup, I utilize a subroute to display a part of the page. I am looking for a way to implement a navigation guard on the subroute to prohi ...

Is there a way to access and read an Excel file stored within the assets folder using Angular?

I need assistance converting an excel file to a JSON format. My excel file is currently stored in the assets folder, and I am looking for guidance on how to access it from app.component.ts. Any help would be greatly appreciated! ...

Concealing the TinyMce Toolbar upon initialization

After setting my content with tinymce, I want to make the toolbar readonly. To achieve this, I subscribed to the editor's init function like so: editor.on('init', () => { editor.setContent(this.value); if (this.disab ...

What is the best way to represent the concept of "having at least one existing property and not having any additional properties" using a mapped type?

Apologies for the slightly lengthy title. Consider the following type: type A = { foo: string; bar: number; baz: boolean; } I want to define a new "partial" type B type B = Partial<A> where B must have at least one property of A and on ...

Is it possible to utilize a slot within a Vue.js loop?

I am encountering an issue with a template that is utilizing v-for to loop through. The template includes a named slot where the name is dynamically assigned within the loop. However, no content is displaying as expected. Can someone help me identify wha ...

Guide on adding checkboxes for each child component in a Vue ads table

<vue-ads-table :columns="fields" :rows="items" :selectable="true" @row-selected="onRowSelected" class="my-table" ...

Refresh the page when the parameter in the URL changes

I'm encountering a small issue that I can't seem to resolve. Currently, I am on the following page: http://example.com:8080/#/user/5ad142e8063ebb0537c5343e There is a link on this page that points to the URL below: http://example.com:8080/#/u ...

Using the Trigger Method in a Vue JS Component with Sibling Components

Seeking assistance once again for a VueJS2 project. Currently, I have a setup with a parent component, along with child1 and child2. The scenario is that the form in child1 needs to receive data from child2, which acts as a table. When a checkbox on a row ...

Accessing the "this" object in Vue.js components

When executing console.log(this) in the doSomething method, it returns "null". I was expecting console.log(this.currentPage) to display "main", but unfortunately, the "this" object is null.. :( Is there a way to access the value of "main" for currentPage ...

What is TS's method of interpreting the intersection between types that have the same named function properties but different signatures (resulting in an error when done

When working with types in Typescript, I encountered an interesting scenario. Suppose we have a type A with two properties that are functions. Now, if we define a type B as the intersection of type A with another type that has the same function properties ...

The object literal can only define properties that are already known, and 'data' is not found in the type 'PromiseLike<T>'

When making a request to a server with my method, the data returned can vary in shape based on the URL. Previously, I would cast the expected interface into the returned object like this: const data = Promise.resolve(makeSignedRequest(requestParamete ...

Enhance the appearance of a custom checkbox component in Angular

I developed a customized toggle switch for my application and integrated it into various sections. Recently, I decided to rework it as a component. However, I am encountering an issue where the toggle switch button does not update in the view (it remains t ...

What is the best way to convert Arabic language HTML into a PDF document on the client side?

Utilizing jsPDF and vue js, I successfully implemented a feature to export PDFs. However, I encountered an issue with Arabic characters not displaying properly. Can anyone provide assistance in resolving this problem? ...

Tips for invoking an Android function from an AngularJS directive?

I am facing an issue with my HTML that uses an AngularJS directive. This HTML file is being used in an Android WebView, and I want to be able to call an Android method from this directive (Learn how to call Android method from JS here). Below is the code ...

Having trouble installing dependencies in a React project with TypeScript due to conflicts

I encountered a TypeScript conflict issue whenever I tried to install any dependency in my project. Despite attempting various solutions such as updating dependencies, downgrading them, and re-installing by removing node_modules and package-lock.json, the ...

Could it be possible for TypeScript inference to directly infer the value and omit the key in the process?

class A { state: B } class B { something: C } class C { a: string; b: boolean; } type MagicType = ... const c: MagicType<A> c.state.a = "123" c.state.b = true; Is it possible to achieve the mentioned functionality without altering the exi ...

Fetching Results from Promise

Repeatedly, this question has been asked in various forms but I still do not understand: I have a resolved promise with a value. When I console.log this object, everything appears to be functioning correctly. I can see exactly what I want to see. My setu ...

Exploring Typescript for Efficient Data Fetching

My main objective is to develop an application that can retrieve relevant data from a mySQL database, parse it properly, and display it on the page. To achieve this, I am leveraging Typescript and React. Here is a breakdown of the issue with the code: I h ...