how to compile time check strongly typed props in vue templates?

Viewed 630

Using Vue with Typescript makes it possible to specify types for props: Strongly typing props of vue components using composition api and typescript typing system

However, as far as I can see these props are only checked at runtime. Here's a simple example component. It has two props a, and b. One is a number and the other a string. Additionally b has a validator, it is only valid if it's equal to hi

<template>
  <p>{{a}}</p>
</template>

<script>
import {defineComponent} from 'vue';
export default defineComponent(
    {
        name: "TestComp",
        props:{
            a:number,
            b:{
                type: String,
                validator:(val)=>val=="hi"
            }
        }
    }
)
</script>

Here's how you could (incorrectly) use the component. The prop a has a wrong type and the prop b fails its validation:

<TestComp a="hi" b="ho"/>

Is it possible to find this bug at compile time? Out of the box, Vue only complains at runtime, with a message such as Invalid prop: custom validator check failed for prop "b".

After searching online, I found that prop type validation can be switched on as an experimental Vetur feature. But this doesn't call the custom validator, so in the example above, Vetur can't find the problem for b.
Also, I'm not always using Vetur and would prefer to have the wrong types trigger an actual compile time error.

1 Answers

For (a): Type definitions

The Typescript / Vue Template compiler does not check for this.

Why? Because the type information is not available to the template compiler.

It is possible to analyze this outside the "normal" template compiler. WebStorm has a check for this.

For (b): Validator

The validation is done at runtime and cannot be checked at compile time.

You can write many of those assertions by adding the exact type to the prop, then WebStorm can check them. When using type checks, it is best use typescript (although you can use /** @type */ comments, too)

<script lang="ts">
import {defineComponent} from 'vue';
export default defineComponent(
    {
        name: "TestComp",
        props:{
            b:{
                type: String as PropType<"hi">,
                validator:(val)=>val==="hi"
            }
        }
    }
)
</script>

Related