2

I have been using withDefaults and defineProps for some time now, but suddenly this has started failing and I cannot understand why!

I've a basic SFC like:

<script
  setup
  lang = "ts">
  const props = withDefaults(defineProps<{
    foo : RegExp
  }>(), {
    foo: /./
  })
</script>
<template>
  <!-- rest of the stuff -->
</template>

The build fails with the error:

error TS2322: Type 'RegExp' is not assignable to type '(props: Readonly<{ foo?: RegExp | undefined; }>) => RegExp'.
  Type 'RegExp' provides no match for the signature '(props: Readonly<{ foo?: RegExp | undefined; }>): RegExp'.

14     foo: /./,
       ~~~

  src/App.vue:11:5
    11     foo?: RegExp;
           ~~~
    The expected type comes from property 'foo' which is declared here on type 'InferDefaults<Readonly<{ foo?: RegExp | undefined; }>>'


Found 1 error in src/App.vue:14

I've setup a minimal reproduction in StackBlitz: https://stackblitz.com/edit/vitejs-vite-du7xik?file=src%2FApp.vue

I'm having a few more issues suddenly related to Typings, with my otherwise working application, but one at a time. Any guidance would help!

EDIT:

The problem only happens when running a production build (as vue-tsc is called only then). On StackBlitz, this would mean running turbo build in the terminal. Apart from that, at least when using IntelliJ, I was also able to see the error in IDE.

Hrishikesh Kokate
  • 1,065
  • 1
  • 8
  • 22

1 Answers1

4

The error means that foo default value was provided as is, while factory function is expected.

It should be:

foo: () => /./,

It's a mistake to specify prop default value directly because it will be shared across multiple component instances, they may affect each other through it. This specifically applies to regex objects which can be stateful.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Oh wow, that was it. Could you please also take a moment to clarify why this happens? For example, I noticed now that, the Vue documentation: https://vuejs.org/api/sfc-script-setup.html#default-props-values-when-using-type-declaration also uses a Function to use an Array, but the String is declared directly. Any specific reason for this difference? When to use a Function vs when can I directly set the value? – Hrishikesh Kokate Aug 28 '22 at 14:45
  • The reason is the same as explained. A string is a primitive and there are no possible problems for the same value to be reused between instances. An array is an object and can be mutated in one instance and affect others. Factory function guarantees that a new object is created for each component instance. Not sure if this practical difference is supported by withDefaults typings because this requires to explicitly support the exceptions for primitive values – Estus Flask Aug 28 '22 at 15:05
  • Thank you for the clear answer and the description. Super helpful! – Hrishikesh Kokate Aug 28 '22 at 16:50