Search code examples
typescriptvue.jsvue-composition-apivue-script-setupvue-validator

How to use validator in vue using setup script, typscript and the composition API


I have the following code example from a tutorial and I try to figure out how to use a validator in a similar way as the example, using the script setup, typescript and the composition API.

props: {
    image: {
      type: String,
      default: require("@/assets/default-poster.png"),
      validator: propValue => {
        const hasImagesDir = propValue.indexOf("@/assets/") > -1;
        const listOfAvailableExt = [".jpeg", ".jpg", ".png"];
        const isValidExt = listOfAvailableExt.some(ext =>
          propValue.endsWith(ext)
        );
        return hasImagesDir && isValidExt;
      }
    }
  }

I know how to declare the type and the default value but I couldn't find a way to use a validator. Is there any function to validate the different properties?

interface Props {
  image: string
}

const props = withDefaults(defineProps<Props>(), {
  image: require("@/assets/default-poster.png")
});

Solution

  • In <script setup>, only the function argument of defineProps() supports validator (as of Vue 3.2.31). The function argument has the same type as the props option:

    defineProps({
      image: {
        type: String,
        default: require("@/assets/default-poster.png"),
        validator: (propValue: string) => {
          const hasImagesDir = propValue.indexOf("@/assets/") > -1;
          const listOfAvailableExt = [".jpeg", ".jpg", ".png"];
          const isValidExt = listOfAvailableExt.some(ext =>
            propValue.endsWith(ext)
          );
          return hasImagesDir && isValidExt;
        }
      }
    })
    

    Note you can't mix the type-only props declaration with the function argument of defineProps(), so any other props would also have to be converted into the option form.

    Alternatively, you could implement your own prop validation:

    <script setup lang="ts">
    interface Props {
      image: string
    }
    
    const props = withDefaults(defineProps<Props>(), {
      image: require("@/assets/default-poster.png")
    });
    
    if (import.meta.env.DEV /* process.env.NODE_ENV === 'development' */) {
      const isValidImage = (propValue: string) => {
        const hasImagesDir = propValue.indexOf("@/assets/") > -1;
        const listOfAvailableExt = [".jpeg", ".jpg", ".png"];
        const isValidExt = listOfAvailableExt.some(ext =>
          propValue.endsWith(ext)
        );
        return hasImagesDir && isValidExt;
      }
    
      if (!isValidImage(props.image)) {
        console.warn(`invalid image: ${props.image}`)
      }
    }
    </script>