@trusktr there is a small difference in your Solid Playground compared with the type definition I provided. Here’s a working example which matches the error thrown by check().
@waldgeist you shouldn’t need to do anything extra to use this. In any normal code (including Meteor.methods), after you’ve called the built-in check() method on a variable, typescript should know what type the variable is:
The only thing you might need to do is npm install -D @types/meteor
@minhna we’re not using a “special version” of anything. The code examples above were contrived simplifications to demonstrate how the type-narrowing definition of the existing check() method works.
@waldgeist no, it’s just the types, so basically if Typescript knows the return type for the server return, the code you call on the client will have knowledge of that type in the client code. So if your method returns an Number the client code will have knowledge that the return is a Number.
As others have said, the check function will handle coercion from one type to another automatically with Meteor’s typescript support set up correctly and after you start up your app (for zodern:types)*
The type signature of check basically says, “if I return successfully without throwing an error, the variable passed into me is definitely of type T, where T is inferred from the schema object passed in”.
In addition to the solutions provided by others, there is also (on npm) the following you can use for type assertions at runtime that have a corresponding effect on your static types:
@sinclair/typebox (supposedly faster than Zod)
purify-ts (for functional programmers, check out the “Coerce” module)
(Amongst many others)
Edit: regarding the asterisk*, I believe that’s the case at least. If not, I had the behaviour with an up to date version of the npm package @types/meteor - either way, I didn’t have to configure any special type overrides or anything, I just needed a strict TSConfig set up with appropriate “includes” references to the corresponding npm/.meteor/local .d.ts files, and it infers the types for me from the schema passed into check.
One other thing that I forgot to mention about zod with zodern:relay is that the React-Hook-Form library also has a fantastic zod integration so you can share you schema’s across client and server, get validated and type safe method params, form data, as well as a type aware form integration. If you are passionate about type safety you’ll absolutely love this, and if you’re not yet, you will be after using tools like this for a while.
There is one thing that’s still missing from Meteor’s type safety story though. Currently if you pass a type to your meteor collection it will set up inference for all of the methods on the collection and when you run a find or find one, it will return a document or a cursor of documents with that type you specified. But what if you have a Profile type and it has a firstName, lastName, bio etc. you pass this to the collection via the type parameter and that’s the type of documents. Then you do something quite normal and you specify that you only want the firstName field in the find method options. Now the type for the return lies and tells our tooling that all the fields are available on each document of the result set. For some this might not seem like that big of a deal, but If you’ve ever worked with a data stack like TRPC with Prisma you understand the DX that you are missing out on. This E2E type safety all the way from the database to the client, this for me, is the Holy Grail, and I’m hoping to make this a reality over the next few months by helping to surface a bunch of code written by Evan Broder for his Jolly Rodger project.
No, I’m just talking TypeScript in this case. I’ve always been a staunch advocate of keeping a flat document structure due to this limitation of Meteor’s mergebox, which is why I created socialize:user-profile for the example scenario, but that’s a topic for another time.
To clarify what I mean above take the following code as an example.
No we see here that we have 2 similar queries to find a single document, the difference is that we restrict the second one to the firstName field using { fields: { firstName: 1 }}. This of course means that the return will be an object with the shape { _id: string, firstName: string } or it will be undefined if no document is found. The issue is that if we examine the information typescript knows about this return, we find out that it thinks we have a full profile when a document is found as exampled by this screenshot using 2 slash to surface TypeScript info.
If you notice, it also doesn’t know that there is going to be an _id field on the document as well.This means TypeScript has given us improper information which is a source of totally preventable runtime errors.
If Meteor is ever to be taken as a serious tool for creating large scale codebases, the type safety story is going to have to get a lot better.