github Effect-TS/effect effect@3.12.6

latest releases: @effect/vitest@0.17.3, @effect/sql-sqlite-wasm@0.29.1, @effect/typeclass@0.31.7...
13 hours ago

Patch Changes

  • #4307 289c13b Thanks @gcanti! - Schema: Enhance error messages for discriminated unions.

    Before

    import { Schema } from "effect"
    
    const schema = Schema.Union(
      Schema.Tuple(Schema.Literal(-1), Schema.Literal(0)).annotations({
        identifier: "A"
      }),
      Schema.Tuple(Schema.NonNegativeInt, Schema.NonNegativeInt).annotations({
        identifier: "B"
      })
    ).annotations({ identifier: "AB" })
    
    Schema.decodeUnknownSync(schema)([-500, 0])
    /*
    throws:
    ParseError: AB
    ├─ { readonly 0: -1 }
    │  └─ ["0"]
    │     └─ Expected -1, actual -500
    └─ B
       └─ [0]
          └─ NonNegativeInt
             └─ From side refinement failure
                └─ NonNegative
                   └─ Predicate refinement failure
                      └─ Expected a non-negative number, actual -500
    */

    After

    import { Schema } from "effect"
    
    const schema = Schema.Union(
      Schema.Tuple(Schema.Literal(-1), Schema.Literal(0)).annotations({
        identifier: "A"
      }),
      Schema.Tuple(Schema.NonNegativeInt, Schema.NonNegativeInt).annotations({
        identifier: "B"
      })
    ).annotations({ identifier: "AB" })
    
    Schema.decodeUnknownSync(schema)([-500, 0])
    /*
    throws:
    ParseError: AB
    -├─ { readonly 0: -1 }
    +├─ A
    │  └─ ["0"]
    │     └─ Expected -1, actual -500
    └─ B
       └─ [0]
          └─ NonNegativeInt
             └─ From side refinement failure
                └─ NonNegative
                   └─ Predicate refinement failure
                      └─ Expected a non-negative number, actual -500
    */
  • #4298 8b4e75d Thanks @KhraksMamtsov! - Added type-level validation for the Effect.Service function to ensure the Self generic parameter is provided. If the generic is missing, the MissingSelfGeneric type will be returned, indicating that the generic parameter must be specified. This improves type safety and prevents misuse of the Effect.Service function.

    type MissingSelfGeneric =
      `Missing \`Self\` generic - use \`class Self extends Service<Self>()...\``
  • #4292 fc5e0f0 Thanks @gcanti! - Improve UnknownException error messages

    UnknownException error messages now include the name of the Effect api that
    created the error.

    import { Effect } from "effect"
    
    Effect.tryPromise(() =>
      Promise.reject(new Error("The operation failed"))
    ).pipe(Effect.catchAllCause(Effect.logError), Effect.runFork)
    
    // timestamp=2025-01-21T00:41:03.403Z level=ERROR fiber=#0 cause="UnknownException: An unknown error occurred in Effect.tryPromise
    //     at fail (.../effect/packages/effect/src/internal/core-effect.ts:1654:19)
    //     at <anonymous> (.../effect/packages/effect/src/internal/core-effect.ts:1674:26) {
    //   [cause]: Error: The operation failed
    //       at <anonymous> (.../effect/scratchpad/error.ts:4:24)
    //       at .../effect/packages/effect/src/internal/core-effect.ts:1671:7
    // }"
  • #4309 004fd2b Thanks @gcanti! - Schema: Enforce Finite Durations in DurationFromNanos.

    This update ensures that DurationFromNanos only accepts finite durations. Previously, the schema did not explicitly enforce this constraint.

    A filter has been added to validate that the duration is finite.

    DurationFromSelf
    +.pipe(
    +  filter((duration) => duration_.isFinite(duration), {
    +    description: "a finite duration"
    +  })
    )
  • #4314 b2a31be Thanks @gcanti! - Duration: make DurationValue properties readonly.

  • #4287 5514d05 Thanks @gcanti! - Array: Fix Either import and correct partition example.

  • #4301 bf5f0ae Thanks @gcanti! - Schema: Fix BigIntFromNumber to enforce upper and lower bounds.

    This update ensures the BigIntFromNumber schema adheres to safe integer limits by applying the following bounds:

    BigIntFromSelf
    +  .pipe(
    +    betweenBigInt(
    +      BigInt(Number.MIN_SAFE_INTEGER),
    +      BigInt(Number.MAX_SAFE_INTEGER)
    +    )
    +  )
  • #4228 3b19bcf Thanks @fubhy! - Fixed conflicting ParseError tags between Cron and Schema

  • #4294 b064b3b Thanks @tim-smart! - ensure cause is rendered in FiberFailure

  • #4307 289c13b Thanks @gcanti! - Schema: Add Support for Infinity in Duration.

    This update adds support for encoding Duration.infinity in Schema.Duration.

    Before

    Attempting to encode Duration.infinity resulted in a ParseError due to the lack of support for Infinity in Schema.Duration:

    import { Duration, Schema } from "effect"
    
    console.log(Schema.encodeUnknownSync(Schema.Duration)(Duration.infinity))
    /*
    throws:
    ParseError: Duration
    └─ Encoded side transformation failure
       └─ HRTime
          └─ [0]
             └─ NonNegativeInt
                └─ Predicate refinement failure
                   └─ Expected an integer, actual Infinity
    */

    After

    The updated behavior successfully encodes Duration.infinity as [ -1, 0 ]:

    import { Duration, Schema } from "effect"
    
    console.log(Schema.encodeUnknownSync(Schema.Duration)(Duration.infinity))
    // Output: [ -1, 0 ]
  • #4300 f474678 Thanks @gcanti! - Schema: update pluck type signature to respect optional fields.

    Before

    import { Schema } from "effect"
    
    const schema1 = Schema.Struct({ a: Schema.optional(Schema.String) })
    
    /*
    const schema2: Schema.Schema<string | undefined, {
        readonly a: string | undefined;
    }, never>
    */
    const schema2 = Schema.pluck(schema1, "a")

    After

    import { Schema } from "effect"
    
    const schema1 = Schema.Struct({ a: Schema.optional(Schema.String) })
    
    /*
    const schema2: Schema.Schema<string | undefined, {
        readonly a?: string | undefined;
    }, never>
    */
    const schema2 = Schema.pluck(schema1, "a")
  • #4296 ee187d0 Thanks @gcanti! - fix: update Cause.isCause type from 'never' to 'unknown'

Don't miss a new effect release

NewReleases is sending notifications on new releases.