meteor-type-validation
v2.2.1
Published
A lightweight set of TypeScript utilities to add proper type inference and validation for your Meteor publications and methods
Downloads
697
Maintainers
Readme
Meteor Type Validation
Improves Meteor's built-in types using declarative API resource definitions.
Installation
Install the package, and optionally valibot
for schema validation.
npm i meteor-type-validation valibot
Defining your Meteor API
This package takes a different approach to defining your Meteor methods and publications. To properly infer types for each resource without resorting to a compilation step, we explicitly export each method/publication we want to expose.
Instead of defining your methods using Meteor.methods(...)
, we export an object with the methods you want to publish.
We have two helper functions for this, defineMethods()
and definePublications()
they're only there for type
inference and just returns the same object you provided.
Example methods
// ./imports/api/topics/methods.ts
import { defineMethods } from 'meteor-type-validation';
import * as v from 'valibot';
const CreateSchema = v.object({
title: v.string(),
});
export default defineMethods({
'topics.create': {
schema: [CreateSchema],
method(topic) { // Method parameters are validated and have proper types
return TopicsCollection.insert(topic);
}
},
'topics.remove': {
schema: [v.string()],
method(topicId) {
return TopicsCollection.remove(topicId);
}
}
});
Example publications
// ./imports/api/topics/server/publications.ts
import { definePublications } from 'meteor-type-validation';
import * as v from 'valibot';
const QuerySchema = v.object({
_id: v.optional(v.string()),
createdBy: v.optional(v.string()),
});
const OptionsSchema = v.object({
limit: v.number(v.maxValue(255))
})
export default definePublications({
'topics': {
schema: [QuerySchema, OptionsSchema],
publish(query, options) {
return TopicsCollection.find(query, options);
}
}
})
Registering your API definitions
Having all your Meteor API resources be defined as exports rather than through a method call, we can now extend and
augment all your resources. But most importantly, we can extend Meteor's types to make things like Meteor.call()
autocomplete and perform type validation.
On the server, import all of your publication and method definitions and add them to one big index object.
// ./imports/api/index.ts
import { exposeMethods, UnwrapMethods } from 'meteor-type-validation'
import TopicMethods from '/imports/api/topics/methods';
import TopicPublications from '/imports/api/topics/server/publications';
export const AllMethods = {
...TopicMethods,
} as const;
export const AllPublications = {
...TopicPublications,
} as const;
Then, in your server startup module, import and expose each resource like you normally would with Meteor.publish()
and Meteor.methods()
.
// ./server/startup.ts
import { AllMethods, AllPublications } from '/imports/api';
import {
exposeMethods,
exposePublications,
UnwrapPublications,
UnwrapMethods
} from 'meteor-type-validation';
Meteor.startup(() => {
exposeMethods(AllMethods);
exposePublications(AllPublications);
});
// This extends Meteor's types so that Meteor.call() and Meteor.subscribe()
// will autocomplete and do all that sweet type checking for you 👌
declare module 'meteor/meteor' {
interface DefinedPublications extends UnwrapPublications<typeof AllPublications> {}
interface DefinedMethods extends UnwrapMethods<typeof AllPublications> {}
}
And that's about it. Whenever you use Meteor.subscribe()
or Meteor.call()
you should see that it both autocompletes
method/publication names, and it type checks your provided parameters.
Notes
If you're using the @types/meteor
package, you might only get auto-completion for publication/method names.
The best way to enforce strict typing for these calls would be to explicitly define the resource name as a generic param.
Meteor.call<'topics.create'>('topics.create', {
title: '...' // strictly type checked
})
Meteor.subscribe<'topics'>('topics', {
createdBy: null // Emits a type error that we were expecting to see here
})
We also export a type helper that have these rules pre-applied, so you won't have to repeat yourself.
import { MeteorApi } from 'meteor-type-validation';
// Typo checks
MeteorApi.call('topics.creatE') // type error: Argument of type `topics.creatE` is...
MeteorApi.subscribe('topics', {
createdBy: null, // type error: `null` is not assignable to `string`
})
License
MIT