Changes the object generics to store the derived type instead of the object shape. This imposes a few limitations on type accuracy at the edges, but dramatically speeds up the type processing by tsc
on the command line and in editor. It also removes the need for the SchemaOf
helper which worked...poorly.
Instead the ObjectSchema
class accepts a plain type as its first generic:
interface Folder {
id: ObjectId,
label: string,
files?: File[]
}
- const folder: SchemaOf<Folder, ObjectId | File> = object({
- id: mixed<ObjectId>().defined(),
- label: string().defined(),
- files: array(mixed<File>().defined())
- })
+ const folder: ObjectSchema<Folder> = object({
+ id: mixed<ObjectId>().defined(),
+ label: string().defined(),
+ files: array(mixed<File>().defined())
+ })
It's a small diff, but big improvement in type accuracy and usability, especially with custom schema for class instances.
Note that the generics on the
object()
factory method are still the "object shape, meaningobject<Folder>()
won't work as expected. This is a compromise between the two strategies for handling generics and allows for an accurate type onobject().getDefault()
A number of the improvements here are made possible by simplifications to yup's API and logic, this introduces a few breaking changes though most are small and easily migrated from.
Nullability and presence
This is the largest, and likely most disruptive change. Prior yup allowed for patterns like:
const nullableRequiredString = string().nullable().required()
nullableRequiredString.cast(null) // -> null
nullableRequiredString.validate(null) // ValidationError("this is required and cannot be null")
This may seem unintuitive behavior (and it is) but allowed for a common client side validation case, where we want to use a single schema to parse server data, as well as validate user input. In other words, a server might return invalid "default" values that should still fail when trying to submit.
Now, nullable()
, defined
and required
are all mutually dependent methods. Meaning string().nullable().defined().required()
produces a schema where the value must be a string, and not null
or undefined
. The effect of this is that the type of a cast()
is now accurate and the same as the type returned from validate
.