DEV Community

Justin Poehnelt
Justin Poehnelt

Posted on β€’ Originally published at justin.poehnelt.com on

3

Strongly Typed Yup Schema in TypeScript

This weekend I have been exploring conditional types in TypeScript to use with Firestore. These take the basic form of T extends U ? X : Y and are used to create a new type based on the type of T. I was curious if I could use this to create a strongly typed Yup schema.

The basic idea is to create a generic function that takes a Yup schema and a type. The function will return a Yup schema that is strongly typed to the type. The function will use a conditional type to determine the type of the schema and return the appropriate schema.

import * as yup from "yup";

export type ConditionalSchema<T> = T extends string
  ? yup.StringSchema
  : T extends number
  ? yup.NumberSchema
  : T extends boolean
  ? yup.BooleanSchema
  : T extends Record<any, any>
  ? yup.AnyObjectSchema
  : T extends Array<any>
  ? yup.ArraySchema<any, any>
  : yup.AnySchema;

export type Shape<Fields> = {
  [Key in keyof Fields]: ConditionalSchema<Fields[Key]>;
};
Enter fullscreen mode Exit fullscreen mode

With those two generic types, we can create a strongly typed Yup schema. These can obviously be extended to include more types and better handle arrays and objects.

Some example usage that keeps the TypeScript compiler happy:

interface Foo {
  stringField: string;
  booleanField: boolean;
}

yup.object<Shape<Foo>>({
  stringField: yup.string().default(""),
  booleanField: yup.boolean().default(false),
});
Enter fullscreen mode Exit fullscreen mode

And it works! πŸŽ‰

Top comments (0)

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!