richardscarrott / ok-computer

λ "Functions all the way down" data validation for JavaScript and TypeScript.
MIT License
79 stars 0 forks source link

Research valid type inference #5

Closed richardscarrott closed 2 years ago

richardscarrott commented 2 years ago

I know a few other libs take runtime validation definitions and infer the TS interface.

Ok computer offers the full expressiveness of JS to define validation logic -- i.e. a validator is a function that could do just about anything -- which I think may make this a little more challenging; however functions are objects, so an annotate fn like this might work:

const annotate = <T, Err = any>(
  validator: Validator<Err>
): Validator<Err> & { __validType: T } => {
  return validator as Validator<Err> & { __validType: T };
};

type InferType<T extends { [key: string | symbol]: { __validType?: any } }> = {
  [Prop in keyof T]: T[Prop]['__validType'];
};

const name = annotate<string>(string);

// type V = InferType<typeof val>;
// type Name = typeof name;
// type OutputType = Name['__validType'];
type Result = InferType<{ a: typeof name }>;

const object2 = <
  Validators extends Record<
    keyof Validators,
    ((val: any, ...parents: any[]) => any) & { __validType?: any }
  >
>(
  validators: Validators
): StructValidator<
  ObjReturnTypes<Validators> & {
    [OBJECT_ROOT]?: string;
  } & IStructure
> & { __validType: InferType<Validators> } =>
  ((...parents: unknown[]) => {
    return {} as any;
  }) as any;

const user = object2({
  name: annotate<string>(string),
  age: annotate<number>(number),
  address: object2({
    line1: annotate<string>(string),
    line2: annotate<string | undefined>(or(nullish, string)),
    city: annotate<string | undefined>(or(nullish, string, minLength(1)))
  })
});

type User = Readonly<typeof user['__validType']>;

const aUser: User = {
  name: 'Dawn',
  age: 32,
  address: {
    line1: 'line 1',
    line2: 'line 2',
    city: ''
  }
};
richardscarrott commented 2 years ago

I guess or and and could also infer their types:

typeof nullish['__validType'] // undefined | null
typeof string['__validType'] // string
typeof or(nullish, string)['__validType'] // undefined | null | string

Feels like a massive abuse of a property which wouldn't exist at runtime though?

richardscarrott commented 2 years ago

https://github.com/richardscarrott/ok-computer/pull/9