Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Props typing in Vue.js 3 with TypeScript

I'm trying to type hint my props in a Vue 3 component, with composition API.

So, I'm doing this:

<script lang="ts">
import FlashInterface from '@/interfaces/FlashInterface';
import { ref } from 'vue';
import { useStore } from 'vuex';

export default {
    props: {
        message: {
            type: FlashInterface,
            required: true
        }
    },
    setup(props): Record<string, unknown> {
        // Stuff
    }
};

My FlashInterface looks like this:

export default interface FlashInterface {
    level: string,
    message: string,
    id?: string
}

This interface works well except in this case where I got this error:

ERROR in src/components/Flash.vue:20:10
TS2693: 'FlashInterface' only refers to a type, but is being used as a value here.
    18 |    props: {
    19 |        message: {
  > 20 |            type: FlashInterface,
       |                  ^^^^^^^^^^^^^^
    21 |            required: true
    22 |        }
    23 |    },

I don't understand why TypeScript thinks this is a value.

What am I missing?

like image 216
chindit Avatar asked Nov 14 '20 07:11

chindit


People also ask

Does Vue 3 support TypeScript?

Vue is written in TypeScript itself and provides first-class TypeScript support. All official Vue packages come with bundled type declarations that should work out-of-the-box.

Can you use TypeScript with Vue?

Now that Vue. js officially supports TypeScript, it's possible to create TypeScript projects from scratch using Vue CLI. However, you still need some third-party packages with custom decorators and features to create a true, complete TypeScript application.

How do you write props in Vue?

To specify the type of prop you want to use in Vue, you will use an object instead of an array. You'll use the name of the property as the key of each property, and the type as the value. If the type of the data passed does not match the prop type, Vue sends an alert (in development mode) in the console with a warning.


2 Answers

You should use it with PropType imported from vue like Object as PropType<FlashInterface>:

import FlashInterface from '@/interfaces/FlashInterface';
import { ref,PropType, defineComponent } from 'vue';
import { useStore } from 'vuex';

export default defineComponent({
    props: {
        message: {
            type: Object as PropType<FlashInterface>,
            required: true
        }
    },
    setup(props) {
            // Stuff
        }
});

Note : you should create your component using defineComponent in order to get the types inference.

script setup

You could define the props using defineProps function in two ways :

<script setup lang="ts">
import FlashInterface from '@/interfaces/FlashInterface';
import { ref,PropType, defineComponent , defineProps} from 'vue';
interface IProps{
   message : FlashInterface
}
const props = defineProps<IProps>()

or

<script setup lang="ts">
...
const props = defineProps({
        message: {
            type: Object as PropType<FlashInterface>,
            required: true
        }
    })
like image 179
Boussadjra Brahim Avatar answered Oct 19 '22 07:10

Boussadjra Brahim


The compiler is complaining about missing a reference for a (custom) constructor during type checking (links to legacy docs but works the same way with the most recent version of Vue).

In Typescript, you might want to think of interfaces as a contract that an entity should conform to, so they aren't really a constructor, and therefore, we need to provide an implementation of those interfaces.

Since you are on Typescript, if you need to keep the interface, consider using the class equivalent:

// Name the constructor whatever you like,
// but I would personally prefix interfaces with an "I"
// to distinguish them with the constructors

class Flash implements FlashInterface {
  level: string;
  message: string;
  id?: string

  constructor() {
    // Be sure to initialize the values for non-nullable props
    this.level = '';
    this.message = '';
  }
}

export default {
  name: 'Home',

  props: {
    message: Flash
  }
}

An excerpt from the doc:

In addition, type can also be a custom constructor function and the assertion will be made with an instanceof check. For example, given the following constructor function exists:

props: {
  message: {
    type: function Person(firstName, lastName) {
      this.firstName = firstName
      this.lastName = lastName
    }
  }
}

And of course, another alternative would be as suggested in the other post with PropType. Either one will do. It's just a matter of preference, I guess.

like image 4
Yom T. Avatar answered Oct 19 '22 05:10

Yom T.