Vue + Typescript "meteor:" type definition

OK, so I’ve got typescript + meteor + VueJs kinda working.

But is there an official (global) way to extend the Vue type definition so it understands the "meteor:" property?

image

FYI, I’m using:

# For .ts files
meteor add typescript
meteor npm install --save-dev @types/meteor
# and for Vue files.
meteor add nathantreid:vue-typescript-babel
# which needs...
meteor npm install --save-dev @babel/plugin-transform-typescript

Thanks!

OK, so for anyone else who’s interested, here’s the solution I’ve come up with. It’s not automagic, but doesn’t require much extra code.

First, the easy bit: allowing the component definition to have a random meteor: property and define the extra properties added to the Vue component ($subscribe, etc). Just put this somewhere:

declare module 'vue/types/options' {
    interface ComponentOptions<V extends Vue> {
        meteor?: any;
    }
}

declare module 'vue/types/vue' {
    interface Vue {
        $subscribe: (name: string, params: any[]) => void;
        $autorun: (fn: () => void) => number;
        $subReady: Record<string, boolean>;
  }
}

Then the tricky bit: allowing data/subscriptions defined within the meteor: property to be correctly typed. Help came via this StackOverflow answer: https://stackoverflow.com/a/60948413/9614402

Just define this function somewhere:

export const withMeteorData = <TData>(data: TData) => {
	return <TMeteorData>() => data as TData & MeteorData;
}

Then, import it into in any Vue component which uses meteor:, then:

data() {
    return withMeteorData({
        // normal reactive data goes here
        loading: false,
    })<{
        // stuff defined in meteor: goes here to get added to the component's types
        apiKey: string;
    }>()
},
meteor: {
    $subscribe: {
        'users_api_key': () => { return [Meteor.userId()]},
    },
    apiKey() {
        return Meteor.users.findOne(Meteor.userId()!, {fields: {apiKey: 1}})!.apiKey || '';
    },
},

If anyone can find a better/automatic solution then please let us know!