Closed ForbesLindesay closed 3 years ago
Added .withParser
helper 🚀
✈️ You can use this to build APIs that are more tolerant, without letting messy data get into your application code:
const TrimmedString = ParsedValue(String, {
name: 'TrimmedString',
parse(value) {
return { success: true, value: value.trim() };
},
test: String.withConstraint(
value =>
value.trim() === value || `Expected the string to be trimmed, but this one has whitespace`,
),
});
TrimmedString.safeParse(' foo bar ')
// => 'foo bar'
🎈You can use it to parse data types that don't exist in JSON like Date
or URL
:
const URLString = ParsedValue(String, {
name: 'URLString',
parse(value) {
try {
return { success: true, value: new URL(value) };
} catch (ex) {
return { success: false, message: `Expected a valid URL but got '${value}'` };
}
},
test: InstanceOf(URL),
serialize(value) {
return { success: true, value: value.href };
},
});
URLString.parse('https://example.com/foo/../');
// => new URL('https://example.com/')
URLString.serialize(new URL('https://example.com'))
// => 'https://example.com'
🤯 You can combine it with other types to make super clean code for upgrading old type definitions:
const Shape = Union(
Record({
version: Literal(1),
size: Number,
}).withParser({
parse: ({ size }) => ({
success: true,
value: { version: 2 as const, width: size, height: size },
}),
}),
Record({ version: Literal(2), width: Number, height: Number }),
);
Shape.parse({version: 1, size: 42})
// => {version: 2, width: 42, height: 42}
Shape.parse({version: 2, width: 42, height: 12}})
// => {version: 2, width: 42, height: 12}
ℹ️ The actual parsing only happens when using the parse
/safeParse
methods.
ℹ️ You can use the .assert
and .test
methods to check data is already correctly formatted.
ℹ️ If you omit the "test" or "serialize" functions, the corresponding operations will always result in an error for that type. This is very useful for Unions, where it lets you have certain options be "parse only"
Add serialize
and safeSerialize
For most types, serialize
is equivalent to parse
and safeSerialize
is equivalent to safeParse
, however if you have any ParsedValue
types (created using the new .withParser
method), these will allow you to apply an inverse transformation.
Renamed guard
to test
guard
is now marked as deprecated
Renamed check
to parse
check
is now marked as deprecated
Renamed validate
to safeParse
validate
is now marked as deprecated
This allows you to define a type that has a different representation for parsed vs. serialized data. The
serialize
method is left as optional, which lets you create parse-only codecs for legacy data while always serializing to the latest format