Skip to content

Commit

Permalink
disallow excess properties for various function options (#4541)
Browse files Browse the repository at this point in the history
  • Loading branch information
fubhy authored Mar 3, 2025
1 parent fcc9e3b commit 9bf8a74
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 49 deletions.
7 changes: 7 additions & 0 deletions .changeset/pretty-plants-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@effect/typeclass": patch
"@effect/platform": patch
"effect": patch
---

Disallowed excess properties for various function options
32 changes: 16 additions & 16 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,13 +788,13 @@ export const once: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<void, E, R>
*/
export const all: <
const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(arg: Arg, options?: O) => All.Return<Arg, O> = fiberRuntime.all

/**
Expand Down Expand Up @@ -837,13 +837,13 @@ export const all: <
* @category Collecting
*/
export const allWith: <
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(
options?: O
) => <const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>>(
Expand Down Expand Up @@ -937,13 +937,13 @@ export declare namespace All {
*/
export type Return<
Arg extends Iterable<EffectAny> | Record<string, EffectAny>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
> = [Arg] extends [ReadonlyArray<EffectAny>] ? ReturnTuple<Arg, IsDiscard<O>, ExtractMode<O>>
: [Arg] extends [Iterable<EffectAny>] ? ReturnIterable<Arg, IsDiscard<O>, ExtractMode<O>>
: [Arg] extends [Record<string, EffectAny>] ? ReturnObject<Arg, IsDiscard<O>, ExtractMode<O>>
Expand Down Expand Up @@ -4181,7 +4181,7 @@ export declare namespace Retry {
* @since 2.0.0
* @category Error handling
*/
export type Return<R, E, A, O extends Options<E>> = Effect<
export type Return<R, E, A, O extends NoExcessProperties<Options<E>, O>> = Effect<
A,
| (O extends { schedule: Schedule.Schedule<infer _O, infer _I, infer _R> } ? E
: O extends { until: Refinement<E, infer E2> } ? E2
Expand Down Expand Up @@ -4325,15 +4325,15 @@ export declare namespace Retry {
* @category Error handling
*/
export const retry: {
<E, O extends Retry.Options<E>>(
<E, O extends NoExcessProperties<Retry.Options<E>, O>>(
options: O
): <A, R>(
self: Effect<A, E, R>
) => Retry.Return<R, E, A, O>
<B, E, R1>(
policy: Schedule.Schedule<B, NoInfer<E>, R1>
): <A, R>(self: Effect<A, E, R>) => Effect<A, E, R1 | R>
<A, E, R, O extends Retry.Options<E>>(
<A, E, R, O extends NoExcessProperties<Retry.Options<E>, O>>(
self: Effect<A, E, R>,
options: O
): Retry.Return<R, E, A, O>
Expand Down Expand Up @@ -7742,12 +7742,12 @@ export const bindAll: {
<
A extends object,
X extends Record<string, Effect<any, any, any>>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(
f: (a: NoInfer<A>) => [Extract<keyof X, keyof A>] extends [never] ? X : `Duplicate keys`,
options?: undefined | O
Expand All @@ -7763,12 +7763,12 @@ export const bindAll: {
<
A extends object,
X extends Record<string, Effect<any, any, any>>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
},
}, O>,
E1,
R1
>(
Expand Down Expand Up @@ -9893,7 +9893,7 @@ export declare namespace Repeat {
* @since 2.0.0
* @category Repetition / Recursion
*/
export type Return<R, E, A, O extends Options<A>> = Effect<
export type Return<R, E, A, O extends NoExcessProperties<Options<A>, O>> = Effect<
(O extends { schedule: Schedule.Schedule<infer Out, infer _I, infer _R> } ? Out
: O extends { until: Refinement<A, infer B> } ? B
: A),
Expand Down Expand Up @@ -9979,15 +9979,15 @@ export declare namespace Repeat {
* @category Repetition / Recursion
*/
export const repeat: {
<O extends Repeat.Options<A>, A>(
<O extends NoExcessProperties<Repeat.Options<A>, O>, A>(
options: O
): <E, R>(
self: Effect<A, E, R>
) => Repeat.Return<R, E, A, O>
<B, A, R1>(
schedule: Schedule.Schedule<B, A, R1>
): <E, R>(self: Effect<A, E, R>) => Effect<B, E, R1 | R>
<A, E, R, O extends Repeat.Options<A>>(
<A, E, R, O extends NoExcessProperties<Repeat.Options<A>, O>>(
self: Effect<A, E, R>,
options: O
): Repeat.Return<R, E, A, O>
Expand Down
10 changes: 5 additions & 5 deletions packages/effect/src/Micro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import type { Predicate, Refinement } from "./Predicate.js"
import { hasProperty, isIterable, isTagged } from "./Predicate.js"
import type { Sink } from "./Sink.js"
import type { Stream } from "./Stream.js"
import type { Concurrency, Covariant, Equals, NotFunction, Simplify } from "./Types.js"
import type { Concurrency, Covariant, Equals, NoExcessProperties, NotFunction, Simplify } from "./Types.js"
import type * as Unify from "./Unify.js"
import { SingleShotGen, YieldWrap, yieldWrapGet } from "./Utils.js"

Expand Down Expand Up @@ -3778,10 +3778,10 @@ export declare namespace All {
*/
export type Return<
Arg extends Iterable<MicroAny> | Record<string, MicroAny>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly discard?: boolean | undefined
}
}, O>
> = [Arg] extends [ReadonlyArray<MicroAny>] ? ReturnTuple<Arg, IsDiscard<O>>
: [Arg] extends [Iterable<MicroAny>] ? ReturnIterable<Arg, IsDiscard<O>>
: [Arg] extends [Record<string, MicroAny>] ? ReturnObject<Arg, IsDiscard<O>>
Expand All @@ -3799,10 +3799,10 @@ export declare namespace All {
*/
export const all = <
const Arg extends Iterable<Micro<any, any, any>> | Record<string, Micro<any, any, any>>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly discard?: boolean | undefined
}
}, O>
>(arg: Arg, options?: O): All.Return<Arg, O> => {
if (Array.isArray(arg) || isIterable(arg)) {
return (forEach as any)(arg, identity, options)
Expand Down
7 changes: 5 additions & 2 deletions packages/effect/src/STM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import * as stm from "./internal/stm/stm.js"
import type * as Option from "./Option.js"
import type { Pipeable } from "./Pipeable.js"
import type { Predicate, Refinement } from "./Predicate.js"
import type { Covariant, MergeRecord, NoInfer } from "./Types.js"
import type { Covariant, MergeRecord, NoExcessProperties, NoInfer } from "./Types.js"
import type * as Unify from "./Unify.js"
import type { YieldWrap } from "./Utils.js"

Expand Down Expand Up @@ -230,7 +230,10 @@ export declare namespace All {
* @category utils
*/
export interface Signature {
<Arg extends ReadonlyArray<STMAny> | Iterable<STMAny> | Record<string, STMAny>, O extends Options>(
<
Arg extends ReadonlyArray<STMAny> | Iterable<STMAny> | Record<string, STMAny>,
O extends NoExcessProperties<Options, O>
>(
arg: Narrow<Arg>,
options?: O
): [Arg] extends [ReadonlyArray<STMAny>] ? ReturnTuple<Arg, IsDiscard<O>>
Expand Down
12 changes: 6 additions & 6 deletions packages/effect/src/internal/effect/circular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,12 +805,12 @@ export const bindAll: {
<
A extends object,
X extends Record<string, Effect.Effect<any, any, any>>,
O extends {
O extends Types.NoExcessProperties<{
readonly concurrency?: Types.Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(
f: (a: A) => [Extract<keyof X, keyof A>] extends [never] ? X : `Duplicate keys`,
options?: undefined | O
Expand All @@ -832,12 +832,12 @@ export const bindAll: {
<
A extends object,
X extends Record<string, Effect.Effect<any, any, any>>,
O extends {
O extends Types.NoExcessProperties<{
readonly concurrency?: Types.Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
},
}, O>,
E1,
R1
>(
Expand All @@ -864,12 +864,12 @@ export const bindAll: {
} = dual((args) => core.isEffect(args[0]), <
A extends object,
X extends Record<string, Effect.Effect<any, any, any>>,
O extends {
O extends Types.NoExcessProperties<{
readonly concurrency?: Types.Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
},
}, O>,
E1,
R1
>(
Expand Down
10 changes: 5 additions & 5 deletions packages/effect/src/internal/fiberRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { currentScheduler, type Scheduler } from "../Scheduler.js"
import type * as Scope from "../Scope.js"
import type * as Supervisor from "../Supervisor.js"
import type * as Tracer from "../Tracer.js"
import type { Concurrency, NoInfer } from "../Types.js"
import type { Concurrency, NoExcessProperties, NoInfer } from "../Types.js"
import { internalCall, yieldWrapGet } from "../Utils.js"
import * as RequestBlock_ from "./blockedRequests.js"
import * as internalCause from "./cause.js"
Expand Down Expand Up @@ -1945,13 +1945,13 @@ const allEither = (
/* @internal */
export const all = <
const Arg extends Iterable<Effect.Effect<any, any, any>> | Record<string, Effect.Effect<any, any, any>>,
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(
arg: Arg,
options?: O
Expand All @@ -1974,13 +1974,13 @@ export const all = <

/* @internal */
export const allWith = <
O extends {
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
}, O>
>(options?: O) =>
<const Arg extends Iterable<Effect.Effect<any, any, any>> | Record<string, Effect.Effect<any, any, any>>>(
arg: Arg
Expand Down
8 changes: 4 additions & 4 deletions packages/effect/src/internal/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1810,14 +1810,14 @@ export const repeat_Effect = dual<

/** @internal */
export const repeat_combined = dual<{
<O extends Effect.Repeat.Options<A>, A>(
<O extends Types.NoExcessProperties<Effect.Repeat.Options<A>, O>, A>(
options: O
): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Repeat.Return<R, E, A, O>
<B, A, R1>(
schedule: Schedule.Schedule<B, A, R1>
): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E, R | R1>
}, {
<A, E, R, O extends Effect.Repeat.Options<A>>(
<A, E, R, O extends Types.NoExcessProperties<Effect.Repeat.Options<A>, O>>(
self: Effect.Effect<A, E, R>,
options: O
): Effect.Repeat.Return<R, E, A, O>
Expand Down Expand Up @@ -1907,15 +1907,15 @@ export const retry_Effect = dual<

/** @internal */
export const retry_combined: {
<E, O extends Effect.Retry.Options<E>>(
<E, O extends Types.NoExcessProperties<Effect.Retry.Options<E>, O>>(
options: O
): <A, R>(
self: Effect.Effect<A, E, R>
) => Effect.Retry.Return<R, E, A, O>
<B, E, R1>(
policy: Schedule.Schedule<B, Types.NoInfer<E>, R1>
): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R1 | R>
<A, E, R, O extends Effect.Retry.Options<E>>(
<A, E, R, O extends Types.NoExcessProperties<Effect.Retry.Options<E>, O>>(
self: Effect.Effect<A, E, R>,
options: O
): Effect.Retry.Return<R, E, A, O>
Expand Down
5 changes: 3 additions & 2 deletions packages/effect/test/Effect/do-notation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as Either from "effect/Either"
import { pipe } from "effect/Function"
import * as Option from "effect/Option"
import * as Util from "effect/test/util"
import type { NoExcessProperties } from "effect/Types"

const expectRight = <R, L>(e: Effect.Effect<R, L>, expected: R) => {
Util.deepStrictEqual(Effect.runSync(Effect.either(e)), Either.right(expected))
Expand Down Expand Up @@ -48,7 +49,7 @@ describe("do notation", () => {

describe("bindAll", () => {
it("succeed", () => {
const getTest = <O extends { mode: "default" | "either" | "validate" }>(options: O) =>
const getTest = <O extends NoExcessProperties<{ mode: "default" | "either" | "validate" }, O>>(options: O) =>
Effect.Do.pipe(
Effect.bind("x", () => Effect.succeed(2)),
Effect.bindAll(({ x }) => ({
Expand Down Expand Up @@ -77,7 +78,7 @@ describe("do notation", () => {
})

it("with failure", () => {
const getTest = <O extends { mode: "default" | "either" | "validate" }>(options: O) =>
const getTest = <O extends NoExcessProperties<{ mode: "default" | "either" | "validate" }, O>>(options: O) =>
Effect.Do.pipe(
Effect.bind("x", () => Effect.succeed(2)),
Effect.bindAll(({ x }) => ({
Expand Down
18 changes: 13 additions & 5 deletions packages/platform/src/HttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type * as Predicate from "effect/Predicate"
import type { Ref } from "effect/Ref"
import type * as Schedule from "effect/Schedule"
import type * as Scope from "effect/Scope"
import type { NoInfer } from "effect/Types"
import type { NoExcessProperties, NoInfer } from "effect/Types"
import type { Cookies } from "./Cookies.js"
import type * as Error from "./HttpClientError.js"
import type * as ClientRequest from "./HttpClientRequest.js"
Expand Down Expand Up @@ -478,7 +478,7 @@ export declare namespace Retry {
* @since 1.0.0
* @category error handling
*/
export type Return<R, E, O extends Effect.Retry.Options<E>> = HttpClient.With<
export type Return<R, E, O extends NoExcessProperties<Effect.Retry.Options<E>, O>> = HttpClient.With<
| (O extends { schedule: Schedule.Schedule<infer _O, infer _I, infer _R> } ? E
: O extends { until: Predicate.Refinement<E, infer E2> } ? E2
: E)
Expand All @@ -498,12 +498,20 @@ export declare namespace Retry {
* @category error handling
*/
export const retry: {
<E, O extends Effect.Retry.Options<E>>(options: O): <R>(self: HttpClient.With<E, R>) => Retry.Return<R, E, O>
<E, O extends NoExcessProperties<Effect.Retry.Options<E>, O>>(
options: O
): <R>(self: HttpClient.With<E, R>) => Retry.Return<R, E, O>
<B, E, R1>(
policy: Schedule.Schedule<B, NoInfer<E>, R1>
): <R>(self: HttpClient.With<E, R>) => HttpClient.With<E, R1 | R>
<E, R, O extends Effect.Retry.Options<E>>(self: HttpClient.With<E, R>, options: O): Retry.Return<R, E, O>
<E, R, B, R1>(self: HttpClient.With<E, R>, policy: Schedule.Schedule<B, E, R1>): HttpClient.With<E, R1 | R>
<E, R, O extends NoExcessProperties<Effect.Retry.Options<E>, O>>(
self: HttpClient.With<E, R>,
options: O
): Retry.Return<R, E, O>
<E, R, B, R1>(
self: HttpClient.With<E, R>,
policy: Schedule.Schedule<B, E, R1>
): HttpClient.With<E, R1 | R>
} = internal.retry

/**
Expand Down
Loading

0 comments on commit 9bf8a74

Please sign in to comment.