0

I am building a simple Vue3 app (using Typescript) and one of the components receives its data via props. With the basic version everything works fine:

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

I then wanted to extend props to add default values, validators, etc.

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

And then TS started to raise issues that I do not understand (all in setup()):


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)'.

for 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) =>...'.

for the line

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

There are a few more but I believe that I will fix them once I understand where the core of the problem is.

WoJ
  • 27,165
  • 48
  • 180
  • 345

2 Answers2

3

The problem here is similar to another question, where only the validator property was a regular function. In your case, both validator and default are regular functions (albeit in different props), which inexplicably breaks the type inference for the props argument in setup(). I'm seeking the root problem in an open question.

Interestingly, your code creates this type for the props argument in setup(), which seems to be an intersection type of keys of 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<...>>>

Workaround

Instead of regular functions, use arrow functions (when functions are needed) 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
    },
  },
})

...which creates this type for the props argument:

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

GitHub demo

tony19
  • 125,647
  • 18
  • 229
  • 307
1

The validator should be an arrow function :

when: {
  type: String,
  default: '',
  validator:(value:string)=>(['today', 'tomorrow', 'later'].includes(value)),
  required:true
 },
 
Boussadjra Brahim
  • 82,684
  • 19
  • 144
  • 164
  • Are you sure? https://v3.vuejs.org/guide/component-props.html#prop-validation shows the version I used. The arrow version works as well, but this does not fix the issues in the question. – WoJ Aug 05 '21 at 18:12