TypeScript 4.3 and SimpleSchema

Hi there! I guess most of you know, that TypeScript is evolving really fast, right? That’s truly great, especially the upcoming template string type improvements. What does it mean? Well, it means we can finally implement a fully typed (subset) of SimpleSchema!

Here’s a full demo. In short, it looks like this:

import { TypedSimpleSchema, validate } from './experimental';

// TypedSimpleSchema has no runtime cost,
// except one extra step in the prototype chain.
const schemaA = new TypedSimpleSchema({
  xs: { type: Array },
  'xs.$': { type: Object },
  'xs.$.a': { type: String },
  'xs.$.b': { type: Number },
  'xs.$.c': { type: Object },
  'xs.$.c.d': { type: Boolean },
});

const schemaB = new TypedSimpleSchema({
  ys: { type: Array },
  'ys.$': { type: schemaA },
});

function foo(value: unknown) {
  validate(schemaB, value);
  // Here `value` is typed!
  // value: {
  //   ys: {
  //       xs: {
  //           a: string;
  //           b: number;
  //           c: {
  //               d: boolean;
  //           };
  //       }[];
  //   }[];
  // }
  return value;
}

There are some limitations, e.g., no support for new SimpleSchema([schema1, schema2]) and shorthand properties (field: String). I also didn’t tested it that much. What do you think?

8 Likes

I just realize that I really don’t know shit about TS. But the prospect that something like this becomes feasible now actually makes it seem worthwile to get into it. If that works, I’ll probably want to do a complete rewrite of my messy schema-driven-ui package in TS.

I don’t know your case, but this kind of “type magic” is not a part of a regular TypeScript codebase. That’s something you create, keep hidden curated, and let everyone benefit.

I also saw your schema-driven-UI – it’s very nice! As it’s using uniforms, maybe I could help you there?

1 Like

this is great news!

Does it also work for model and onSubmit on uniform forms? So if i pass any typedschema(-bridge), it will type check model and onSubmit?

That’s an interesting idea! I’d have to experiment with that, but it may be possible.

In the project, I had been working on, i had really huge simple-schemas (for the main data collection I have a file with 783 lines just for the stitched together schemas, and that’s in coffeescript, so add 40-50% to that number to get the lines of JS/TS). So I wouldn’t really mind a couple of lines of code to get that typed.

I am greatfull for all the help I can get with this project (especially since I will now have to work on that on my free time and not during my regular workday anymore).

I get that - I saw (and created) much larger schemas. (That’s not good, I know.) And what I meant is that there’s no need to redefine all of these types at all - it’s all defined once and then type inference does its job. And it doesn’t need to be your code - it can be a package.

About the project – I’ll DM you.

@radekmie maybe it just needs to have the right generic types (unless it already has).

something like:

type AutoformComponent<T extends Record<string, unknown>> = React.FC<{
  model: T,
  onSubmit: (m: T) => void,
  schema: SchemaBridge<T>
}>

I guess if you pass a model of certain type, TS will also check the rest (so schema and onSubmit has to be compatible)

Well, it’s quite similar, but takes defaultValues into consideration. We could lift it of the onSubmit (model should be complete then), but it won’t really help otherwise.

But your idea is good: a simple wrapper, similar to the TypedSimpleSchema, would be enough.