Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you type hint Vue props with typescript interfaces?

Really hitting my head against a wall on this one. I remember working in Angular that TS interfaces can be used to type hint parameters.

I'd like to do the same for props in Vue.

Any ideas? Code is as follows but the check is only made against a standard Object so passing in ANY object is valid:

import Vue from 'vue';
import Person from './../models/Person';

export default Vue.extend({
  name: 'HelloWorld',
  props: {
    person: {
        type: Object as () => Person
    },
  },
});

Interface as follows:

export default interface Person {
    firstName: string;
    lastName: string;
}
like image 261
DevLime Avatar asked Oct 04 '19 18:10

DevLime


People also ask

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.

Does vue2 support TypeScript?

You should also be familiar with Vue, vue-loader, and webpack. Vue 2 already has good support for TypeScript, and the recently published Vue 2.7 backported a lot of useful features from Vue 3, like composition API, <script setup> , and defineComponent , further improving the developer experience of TypeScript in Vue.

How do I add TS to Vue?

To let Typescript enters into your Vue components, 2 additions are mandatory in each component file: Adding the lang="ts" attribute to the script tag so that Typescript can recognized it.

How do I pass Vue components to Props?

Function modeThe URL /search?q=vue would pass {query: 'vue'} as props to the SearchUser component. Try to keep the props function stateless, as it's only evaluated on route changes. Use a wrapper component if you need state to define the props, that way vue can react to state changes.


2 Answers

Yep - so turns out you can't use interfaces. Makes total sense in hindsight when you consider things like type-hinting in PHP7.

The answer is to apply the interface to a class and the type hint using that class instead. With abstraction layers, my worries about having to apply the wrong class to a type hint were unfounded as any class extending or implementing the Person class will be a valid value to pass to the person prop.

export default interface NameInterface {
    firstName: string;
    lastName: string;
}
import NameInterface from './../interfaces/NameInterface';
export default class Person implements NameInterface {

    firstName: string;
    lastName: string;

    constructor( firstName: string, lastName: string ) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
<script lang="ts">
import Vue from 'vue';
import Person from './../models/Person';

export default Vue.extend({
  name: 'HelloWorld',
  props: {
    person: {
        type: Person
    },
  },
});
</script>
like image 140
DevLime Avatar answered Sep 20 '22 13:09

DevLime


If you're using classes instead of Vue.extend you can use the @Prop() decorator (from vue-property-decorator) to have interfaces as type parameters.

With OP's interface:

export default interface Person {
    firstName: string;
    lastName: string;
}

The class declaration would become:

import {Component, Prop, Vue} from 'vue-property-decorator';
import Person from './../models/Person';

@Component
export default class HelloWorld extends vue {
    @Prop() person : Person;
}

(Source on GitHub)


You could also use PropType<FooBar> in place of Object as () => FooBar (see the end of this medium article), but it has the same issues as OP mentioned.

like image 23
sonrad10 Avatar answered Sep 20 '22 13:09

sonrad10