Why is this an issue?

Vue validates a prop’s runtime type by comparing incoming values against the constructor referenced in the prop’s type field: constructors such as String, Number, Boolean, Array, Object, Date, Function, Symbol, Error, or a custom class. This only works if type holds an actual reference to that constructor, for example type: String.

It is easy to write a value that merely looks like a constructor instead of being one: a quoted string (type: 'String'), a template literal, or the result of a binary or update expression. None of these are functions, so Vue has nothing to run its instanceof/typeof checks against.

When this happens, Vue’s prop validator does not just skip the check silently. In Vue 3, as soon as a value is passed for that prop, Vue throws TypeError: Right-hand side of 'instanceof' is not an object while rendering the component in development, crashing it. In Vue 2, the same failure is caught internally and downgraded to a console warning, Invalid prop type: "…​" is not a constructor, so the component still renders but the intended type is never actually checked. In production builds of either version, prop validation is stripped entirely, so neither the crash nor the warning happens there, but the type contract is also never enforced: the code looks like it validates the prop, when in fact it never can.

This rule also checks each element individually inside an array-shorthand type, for example type: ['String', Number], and applies to prop declarations in both the Options API props option and the defineProps macro used in <script setup>.

To fix this, replace the offending value with the constructor it was meant to reference.

Exceptions

This rule does not flag type: null. Vue’s own convention for that value is to accept a prop of any type, so it is a deliberate choice rather than a mistaken stand-in for a constructor.

Code examples

Noncompliant code example

<script>
export default {
  props: {
    name: {
      type: 'String' // Noncompliant: "String" is a string, not the String constructor
    },
    role: {
      type: ['String', Number] // Noncompliant: "String" inside the array is not a constructor
    }
  }
}
</script>

Compliant solution

<script>
export default {
  props: {
    name: {
      type: String
    },
    role: {
      type: [String, Number]
    }
  }
}
</script>

Noncompliant code example

<script setup>
defineProps({
  status: {
    type: `String` // Noncompliant: a template literal is not the String constructor
  }
})
</script>

Compliant solution

<script setup>
defineProps({
  status: {
    type: String
  }
})
</script>

Resources

Documentation