Search code examples
typescriptvue.jsvuejs3type-hintingvue-composition-api

Not receiving any error on unspecified interface object types when compiling


Hi I'm testing out the Vue composition API with Types

I'm trying to get an error when an interface does not meet the types specified for that interface.

I'm successful in implementing the interface/types that are being expected and I get auto suggestions from my IDE so it looks like it works, but when compiling I don't get any errors when trying to pass let's say a number to a string type.

Here I provide a simple sample

Vue file:

<template>
  <div class="flex flex-col">
    <h1 class="flex justify-center">Test View</h1>
    <TestComponent
      :dataset="{
        strCustomerName: 12345,
      }"
    />
  </div>
</template>
<script setup lang="ts">
import TestComponent from "@/components/TestComponent.vue";
</script>

This Vue file is just importing a component and sending with it an object named dataset.

Test component

<template>
  <h1 class="text-9x1 flex">Hello {{ props.dataset.strCustomerName }}</h1>
</template>

<script setup lang="ts">
import { defineProps } from "vue";

type FormType = {
  strCustomerName: string;
};

interface FormProperties {
  dataset: {
    type: FormType;
    required: true;
  };
}

const props = defineProps<FormProperties>();

console.log("We are props: ", props.dataset);
</script>

Then with this test component, I am trying to tell Vue that I am expecting a dataset object to be passed as a property in the FormProperties, I'm then trying to tell Vue that I want a certain structure from that object which is the FormType where the problem in the example above is that strCustomerName is set to be a string but when I'm passing a number it just goes straight through without any error. I can even pass a key that is not there like if I wanted to use the view file like this:

<template>
  <div class="flex flex-col">
    <h1 class="flex justify-center">Test View</h1>
    <TestComponent
      :dataset="{
        strCustomerHasAName: 'please give me an error'
      }"
    />
  </div>
</template>
<script setup lang="ts">
import TestComponent from "@/components/TestComponent.vue";
</script>

So basically why am I not getting an error when passing wrong types? or keys that are not defined in the FormType object?

Is this the normal behavior or can I actually do something about it?


Solution

  • Using defineProps

    The type declaration for defineProps specifies only the type of every prop, so in your case, defineProps<FormProperties>() tells Vue to create a prop named dataset that has two fields:

    • type, which is of type FormType, which has a strCustomerName property, which is a string.

    • required, which is of type true (i.e., it can only be true, and any other value would result in an error).

    It looks like you were actually trying to use the runtime declaration with defineProps, but that must be given as a function argument to defineProps:

    import type { PropType } from 'vue'
    
    defineProps({
      dataset: {
        type: Object as PropType<FormType>,
        required: true,
      }
    })
    

    Or if you'd rather use the type declaration, update FormProperties to contain only the data fields:

    type FormType = {
      strCustomerName: string;
    };
    
    interface FormProperties {
      dataset: FormType;
    }
    
    defineProps<FormProperties>();
    

    You can't mix the two. defineProps receives either the type declaration, or the function argument, not both.

    Detecting the error

    If you used Volar (the official VS Code extension for Vue), you would've seen an error for your original code:

    Template error shown in VS Code

    Or if you used vue-tsc for typechecking, you would've seen the error in the console:

    $ vue-tsc --noEmit
    src/components/MyComponent.vue:2:52 - error TS2339: Property 'strCustomerName' does not exist on type '{ type: FormType; required: true; }'.
    
    2   <h1 class="text-9x1 flex">Hello {{ props.dataset.strCustomerName }}</h1>
                                                         ~~~~~~~~~~~~~~~
    
    
    Found 1 error in src/components/MyComponent.vue:2