Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@effect/schema@0.67.0
Minor Changes
#2634
d7e4997
Thanks @gcanti! - ## Simplifying Type ExtractionWhen we work with schemas, it's common to need to extract their types automatically.
To make this easier, we've made some changes to the
Schema
interface.Now, you can easily access
Type
andEncoded
directly from a schema without the need forSchema.Schema.Type
andSchema.Schema.Encoded
.Default Constructors
When dealing with data, creating values that match a specific schema is crucial.
To simplify this process, we've introduced default constructors for various types of schemas:
Struct
s,filter
s, andbrand
s.Let's dive into each of them with some examples to understand better how they work.
Example (
Struct
)Example (
filter
)Example (
brand
)When utilizing our default constructors, it's important to grasp the type of value they generate. In the
MyBrand
example, the return type of the constructor isnumber & Brand<"MyNumber">
, indicating that the resulting value is anumber
with the added branding "MyNumber".This differs from the filter example where the return type is simply
number
. The branding offers additional insights about the type, facilitating the identification and manipulation of your data.Note that default constructors are "unsafe" in the sense that if the input does not conform to the schema, the constructor throws an error containing a description of what is wrong. This is because the goal of default constructors is to provide a quick way to create compliant values (for example, for writing tests or configurations, or in any situation where it is assumed that the input passed to the constructors is valid and the opposite situation is exceptional).
To have a "safe" constructor, you can use
Schema.validateEither
:Default Constructor Values
When constructing objects, it's common to want to assign default values to certain fields to simplify the creation of new instances.
Our new
Schema.withConstructorDefault
combinator allows you to effortlessly manage the optionality of a field in your default constructor.Example
Defaults are lazily evaluated, meaning that a new instance of the default is generated every time the constructor is called:
Note how the
timestamp
field varies.Defaults can also be applied using the
Class
API:Default values are also "portable", meaning that if you reuse the same property signature in another schema, the default is carried over:
Defaults can also be applied using the
Class
API:Default Decoding Values
Our new
Schema.withDecodingDefault
combinator makes it easy to handle the optionality of a field during the decoding process.If you want to set default values both for the decoding phase and for the default constructor, you can use
Schema.withDefaults
:Refactoring of Custom Message System
We've refactored the system that handles user-defined custom messages to make it more intuitive.
Now, custom messages no longer have absolute precedence by default. Instead, it becomes an opt-in behavior by explicitly setting a new flag
override
with the valuetrue
. Let's see an example:Previous Approach
As you can see, no matter where the decoding error is raised, the same error message will always be presented because in the previous version, the custom message by default overrides those generated by previous filters.
Now, let's see how the same schema works with the new system.
Current Approach
To restore the old behavior (for example, to address the scenario where a user wants to define a single cumulative custom message describing the properties that a valid value must have and does not want to see default messages), you need to set the
override
flag totrue
:The new system is particularly useful when the schema on which custom messages are defined is more complex than a scalar value (like
string
ornumber
), for example, if it's a struct containing a field that is an array of structs. Let's see an example that illustrates how convenient it is to rely on default messages when the decoding error occurs in a nested structure:In the previous version, we would have received the message "error_min_length_field" for any decoding error, which is evidently suboptimal and has now been corrected.
Filter API Interface
We've introduced a new API interface to the
filter
API. This allows you to access the refined schema using the exposedfrom
field:The signature of the
filter
function has been simplified and streamlined to be more ergonomic when setting a default message. In the new signature offilter
, the type of the predicate passed as an argument is as follows:with the following semantics:
true
means the filter is successful.false
orundefined
means the filter fails and no default message is set.string
means the filter fails and the returned string is used as the default message.ParseIssue
means the filter fails and the returned ParseIssue is used as an error.Let's see an example of how it worked before and how it works now.
Before
Now
JSON Schema Compiler Refactoring
The JSON Schema compiler has been refactored to be more user-friendly. Now, the
make
API attempts to produce the optimal JSON Schema for the input part of the decoding phase. This means that starting from the most nested schema, it traverses the chain, including each refinement, and stops at the first transformation found.Let's see an example:
Now, let's compare the JSON Schemas produced in both the previous and new versions.
Before
As you can see, the JSON Schema produced has:
foo
field, correctly modeled with a constraint ("minLength": 2
)bar
fieldThis happens because in the previous version, the
JSONSchema.make
API by default produces a JSON Schema for theType
part of the schema. That is:However, typically, we are interested in generating a JSON Schema for the input part of the decoding process, i.e., in this case for:
At first glance, a possible solution might be to generate the JSON Schema of
Schema.encodedSchema(schema)
:But here's what the result would be:
As you can see, we lost the
"minLength": 2
constraint, which is the useful part of precisely defining our schemas using refinements.After
Now, let's see what
JSONSchema.make
API produces by default for the same schema:As you can verify, the refinement has been preserved.
Improve
extend
to support refinements andsuspend
ed schemasNow
extend
supports extending refinements, so you can do something like this:We've also added support for
Schema.suspend
. Here's an example:Patches
AST
AST.toString
to honorreadonly
modifiersAST.toString
for refinementsSchema
BrandSchema
fromfromBrand
SchemaClass
interfaceAnnotableClass
interfaceextend
: add support for refinements, closes From Discord: Runtime Error on Extending Structs with Filter in TypeScript #2642pattern
json schema annotation toTrimmed
parseNumber
number transformationTaggedClass
api interface (exposing a_tag
field)TaggedErrorClass
api interface (exposing a_tag
field)TaggedRequestClass
api interface (exposing a_tag
field)DateFromNumber
schemaSchema.Schema.AsSchema
type-level helper to facilitate working with generic schemas.Other Breaking Changes
fast-check
frompeerDependencies
todependencies
AST
add
path
argument toCompiler
APIremove
hash
function, you can replace it with the following code:JSONSchema
extend all interfaces with
JsonSchemaAnnotations
Schema
replace numerous API interfaces with class-based schema definitions
rename
$Array
API interface to `Array# @effect/schemarename
$Record
API interface to `Record# @effect/schemarename
$ReadonlyMap
API interface to `ReadonlyMap# @effect/schemarename
$Map
API interface to `Map# @effect/schemarename
$ReadonlySet
API interface to `ReadonlySet# @effect/schemarename
$Set
API interface to `Set# @effect/schemaremove
asBrandSchema
utilitychange
BrandSchema
interfaceremove
hash
functionfrom
to
Previously, you could directly use the
Brand.Constructor
, but now you need to use itsmake
constructor:Before
Now
@effect/cli@0.36.22
Patch Changes
d7e4997
]:@effect/experimental@0.16.3
Patch Changes
d7e4997
]:@effect/platform@0.53.3
Patch Changes
d7e4997
]:@effect/platform-browser@0.33.18
Patch Changes
@effect/platform-bun@0.34.9
Patch Changes
@effect/platform-node@0.49.3
Patch Changes
@effect/platform-node-shared@0.4.22
Patch Changes
@effect/rpc@0.30.22
Patch Changes
d7e4997
]:@effect/rpc-http@0.28.22
Patch Changes
d7e4997
]:@effect/sql@0.2.5
Patch Changes
d7e4997
]:@effect/sql-mssql@0.2.5
Patch Changes
@effect/sql-mysql2@0.2.5
Patch Changes
@effect/sql-pg@0.2.5
Patch Changes
@effect/sql-sqlite-bun@0.2.5
Patch Changes
@effect/sql-sqlite-node@0.2.5
Patch Changes
@effect/sql-sqlite-react-native@0.3.5
Patch Changes
@effect/sql-sqlite-wasm@0.2.5
Patch Changes