Skip to content

Schema Projections

Sometimes, you may want to create a new schema based on an existing one, focusing specifically on either its Type or Encoded aspect. The Schema module provides several functions to make this possible.

The Schema.typeSchema function is used to extract the Type portion of a schema, resulting in a new schema that retains only the type-specific properties from the original schema. This excludes any initial encoding or transformation logic applied to the original schema.

Function Signature

declare const typeSchema: <A, I, R>(schema: Schema<A, I, R>) => Schema<A>

Example (Extracting Only Type-Specific Properties)

import {
import Schema
Schema
} from "effect"
const
const Original: Schema.Struct<{
quantity: Schema.filter<Schema.Schema<number, string, never>>;
}>
Original
=
import Schema
Schema
.
function Struct<{
quantity: Schema.filter<Schema.Schema<number, string, never>>;
}>(fields: {
quantity: Schema.filter<Schema.Schema<number, string, never>>;
}): Schema.Struct<...> (+1 overload)

@since3.10.0

Struct
({
quantity: Schema.filter<Schema.Schema<number, string, never>>
quantity
:
import Schema
Schema
.
class NumberFromString

This schema transforms a string into a number by parsing the string using the parse function of the effect/Number module.

It returns an error if the value can't be converted (for example when non-numeric characters are provided).

The following special string values are supported: "NaN", "Infinity", "-Infinity".

@since3.10.0

NumberFromString
.
Pipeable.pipe<typeof Schema.NumberFromString, Schema.filter<Schema.Schema<number, string, never>>>(this: typeof Schema.NumberFromString, ab: (_: typeof Schema.NumberFromString) => Schema.filter<Schema.Schema<number, string, never>>): Schema.filter<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const greaterThanOrEqualTo: <number>(min: number, annotations?: Schema.Annotations.Filter<number, number> | undefined) => <I, R>(self: Schema.Schema<number, I, R>) => Schema.filter<Schema.Schema<number, I, R>>

This filter checks whether the provided number is greater than or equal to the specified minimum.

@since3.10.0

greaterThanOrEqualTo
(2))
})
// This creates a schema where 'quantity' is defined as a number
// that must be greater than or equal to 2.
const
const TypeSchema: Schema.SchemaClass<{
readonly quantity: number;
}, {
readonly quantity: number;
}, never>
TypeSchema
=
import Schema
Schema
.
const typeSchema: <{
readonly quantity: number;
}, {
readonly quantity: string;
}, never>(schema: Schema.Schema<{
readonly quantity: number;
}, {
readonly quantity: string;
}, never>) => Schema.SchemaClass<{
readonly quantity: number;
}, {
readonly quantity: number;
}, never>

The typeSchema function allows you to extract the Type portion of a schema, creating a new schema that conforms to the properties defined in the original schema without considering the initial encoding or transformation processes.

@since3.10.0

typeSchema
(
const Original: Schema.Struct<{
quantity: Schema.filter<Schema.Schema<number, string, never>>;
}>
Original
)
// TypeSchema is equivalent to:
const
const TypeSchema2: Schema.Struct<{
quantity: Schema.filter<Schema.Schema<number, number, never>>;
}>
TypeSchema2
=
import Schema
Schema
.
function Struct<{
quantity: Schema.filter<Schema.Schema<number, number, never>>;
}>(fields: {
quantity: Schema.filter<Schema.Schema<number, number, never>>;
}): Schema.Struct<...> (+1 overload)

@since3.10.0

Struct
({
quantity: Schema.filter<Schema.Schema<number, number, never>>
quantity
:
import Schema
Schema
.
class Number
export Number

@since3.10.0

Number
.
Pipeable.pipe<typeof Schema.Number, Schema.filter<Schema.Schema<number, number, never>>>(this: typeof Schema.Number, ab: (_: typeof Schema.Number) => Schema.filter<Schema.Schema<number, number, never>>): Schema.filter<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const greaterThanOrEqualTo: <number>(min: number, annotations?: Schema.Annotations.Filter<number, number> | undefined) => <I, R>(self: Schema.Schema<number, I, R>) => Schema.filter<Schema.Schema<number, I, R>>

This filter checks whether the provided number is greater than or equal to the specified minimum.

@since3.10.0

greaterThanOrEqualTo
(2))
})

The Schema.encodedSchema function enables you to extract the Encoded portion of a schema, creating a new schema that matches the original properties but omits any refinements or transformations applied to the schema.

Function Signature

declare const encodedSchema: <A, I, R>(
schema: Schema<A, I, R>
) => Schema<I>

Example (Extracting Encoded Properties Only)

import {
import Schema
Schema
} from "effect"
const
const Original: Schema.Struct<{
quantity: Schema.filter<Schema.Schema<string, string, never>>;
}>
Original
=
import Schema
Schema
.
function Struct<{
quantity: Schema.filter<Schema.Schema<string, string, never>>;
}>(fields: {
quantity: Schema.filter<Schema.Schema<string, string, never>>;
}): Schema.Struct<...> (+1 overload)

@since3.10.0

Struct
({
quantity: Schema.filter<Schema.Schema<string, string, never>>
quantity
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
.
Pipeable.pipe<typeof Schema.String, Schema.filter<Schema.Schema<string, string, never>>>(this: typeof Schema.String, ab: (_: typeof Schema.String) => Schema.filter<Schema.Schema<string, string, never>>): Schema.filter<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const minLength: <string>(minLength: number, annotations?: Schema.Annotations.Filter<string, string> | undefined) => <I, R>(self: Schema.Schema<string, I, R>) => Schema.filter<...>

@since3.10.0

minLength
(3))
})
// This creates a schema where 'quantity' is just a string,
// disregarding the minLength refinement.
const
const Encoded: Schema.SchemaClass<{
readonly quantity: string;
}, {
readonly quantity: string;
}, never>
Encoded
=
import Schema
Schema
.
const encodedSchema: <{
readonly quantity: string;
}, {
readonly quantity: string;
}, never>(schema: Schema.Schema<{
readonly quantity: string;
}, {
readonly quantity: string;
}, never>) => Schema.SchemaClass<{
readonly quantity: string;
}, {
readonly quantity: string;
}, never>

The encodedSchema function allows you to extract the Encoded portion of a schema, creating a new schema that conforms to the properties defined in the original schema without retaining any refinements or transformations that were applied previously.

@since3.10.0

encodedSchema
(
const Original: Schema.Struct<{
quantity: Schema.filter<Schema.Schema<string, string, never>>;
}>
Original
)
// Encoded is equivalent to:
const
const Encoded2: Schema.Struct<{
quantity: typeof Schema.String;
}>
Encoded2
=
import Schema
Schema
.
function Struct<{
quantity: typeof Schema.String;
}>(fields: {
quantity: typeof Schema.String;
}): Schema.Struct<{
quantity: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
quantity: typeof Schema.String
quantity
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
})

The Schema.encodedBoundSchema function is similar to Schema.encodedSchema but preserves the refinements up to the first transformation point in the original schema.

Function Signature

declare const encodedBoundSchema: <A, I, R>(
schema: Schema<A, I, R>
) => Schema<I>

The term “bound” in this context refers to the boundary up to which refinements are preserved when extracting the encoded form of a schema. It essentially marks the limit to which initial validations and structure are maintained before any transformations are applied.

Example (Retaining Initial Refinements Only)

import {
import Schema
Schema
} from "effect"
const
const Original: Schema.Struct<{
foo: Schema.SchemaClass<string, string, never>;
}>
Original
=
import Schema
Schema
.
function Struct<{
foo: Schema.SchemaClass<string, string, never>;
}>(fields: {
foo: Schema.SchemaClass<string, string, never>;
}): Schema.Struct<{
foo: Schema.SchemaClass<string, string, never>;
}> (+1 overload)

@since3.10.0

Struct
({
foo: Schema.SchemaClass<string, string, never>
foo
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
.
Pipeable.pipe<typeof Schema.String, Schema.filter<Schema.Schema<string, string, never>>, Schema.SchemaClass<string, string, never>>(this: typeof Schema.String, ab: (_: typeof Schema.String) => Schema.filter<...>, bc: (_: Schema.filter<...>) => Schema.SchemaClass<...>): Schema.SchemaClass<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const minLength: <string>(minLength: number, annotations?: Schema.Annotations.Filter<string, string> | undefined) => <I, R>(self: Schema.Schema<string, I, R>) => Schema.filter<...>

@since3.10.0

minLength
(3),
import Schema
Schema
.
const compose: <string, string, never, string>(to: Schema.Schema<string, string, never>) => <A, R1>(from: Schema.Schema<string, A, R1>) => Schema.SchemaClass<string, A, R1> (+7 overloads)

@since3.10.0

compose
(
import Schema
Schema
.
class Trim

This schema allows removing whitespaces from the beginning and end of a string.

@since3.10.0

Trim
)
)
})
// The EncodedBoundSchema schema preserves the minLength(3) refinement,
// ensuring the string length condition is enforced
// but omits the Schema.Trim transformation.
const
const EncodedBoundSchema: Schema.SchemaClass<{
readonly foo: string;
}, {
readonly foo: string;
}, never>
EncodedBoundSchema
=
import Schema
Schema
.
const encodedBoundSchema: <{
readonly foo: string;
}, {
readonly foo: string;
}, never>(schema: Schema.Schema<{
readonly foo: string;
}, {
readonly foo: string;
}, never>) => Schema.SchemaClass<{
readonly foo: string;
}, {
readonly foo: string;
}, never>

The encodedBoundSchema function is similar to encodedSchema but preserves the refinements up to the first transformation point in the original schema.

@since3.10.0

encodedBoundSchema
(
const Original: Schema.Struct<{
foo: Schema.SchemaClass<string, string, never>;
}>
Original
)
// EncodedBoundSchema is equivalent to:
const
const EncodedBoundSchema2: Schema.Struct<{
foo: Schema.filter<Schema.Schema<string, string, never>>;
}>
EncodedBoundSchema2
=
import Schema
Schema
.
function Struct<{
foo: Schema.filter<Schema.Schema<string, string, never>>;
}>(fields: {
foo: Schema.filter<Schema.Schema<string, string, never>>;
}): Schema.Struct<{
foo: Schema.filter<Schema.Schema<string, string, never>>;
}> (+1 overload)

@since3.10.0

Struct
({
foo: Schema.filter<Schema.Schema<string, string, never>>
foo
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
.
Pipeable.pipe<typeof Schema.String, Schema.filter<Schema.Schema<string, string, never>>>(this: typeof Schema.String, ab: (_: typeof Schema.String) => Schema.filter<Schema.Schema<string, string, never>>): Schema.filter<...> (+21 overloads)
pipe
(
import Schema
Schema
.
const minLength: <string>(minLength: number, annotations?: Schema.Annotations.Filter<string, string> | undefined) => <I, R>(self: Schema.Schema<string, I, R>) => Schema.filter<...>

@since3.10.0

minLength
(3))
})