DevLime
DevLime

Reputation: 1027

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;
}

Upvotes: 19

Views: 21520

Answers (3)

AvahW
AvahW

Reputation: 2201

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 archived version), but it has the same issues as OP mentioned.

warning: the archived url gets stuck in a refresh loop unless you disable javascript

Upvotes: 4

Hubert Misonia
Hubert Misonia

Reputation: 171

<script lang="ts">
import Person from './../models/Person';

export default({
  name: 'HelloWorld',
  props: {
    person: {
        type: Object as ()=> Person
    },
  },
});
</script>

Upvotes: 17

DevLime
DevLime

Reputation: 1027

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>

Upvotes: 5

Related Questions