Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/__tests__/definition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import * as Exit from "effect/Exit";
import * as Fiber from "effect/Fiber";
import * as Option from "effect/Option";
import * as Result from "effect/Result";
import * as Schema from "effect/Schema";
import { TestClock } from "effect/testing";
import * as WorkflowEngine from "effect/unstable/workflow/WorkflowEngine";
import { describe, expect, expectTypeOf, it } from "vitest";
import { handle, implementActivities, type ActivityRunner } from "../activities.js";
import {
continueAsNew,
defineActivity,
executeChild,
sleepUntil,
version,
Expand Down Expand Up @@ -80,6 +82,38 @@ const _types = () => {
// @ts-expect-error wrong payload shape
Charge({ orderId: 1 });

// Omitted schemas retain their runtime defaults in the type channels.
const Defaults = defineActivity("defaults", { payload: { id: Schema.String } });
const defaults = Defaults({ id: "x" });
expectTypeOf<Effect.Success<typeof defaults>>().toEqualTypeOf<void>();
expectTypeOf<Effect.Error<typeof defaults>>().toEqualTypeOf<never>();

// An error schema can still be inferred while success defaults to void.
const ErrorOnly = defineActivity("errorOnly", {
payload: { id: Schema.String },
error: CardDeclined,
});
const errorOnly = ErrorOnly({ id: "x" });
expectTypeOf<Effect.Success<typeof errorOnly>>().toEqualTypeOf<void>();
expectTypeOf<Effect.Error<typeof errorOnly>>().toEqualTypeOf<typeof CardDeclined.Type>();

defineActivity<"missingSuccess", { id: typeof Schema.String }, typeof Schema.String>(
"missingSuccess",
// @ts-expect-error a non-default success generic requires its runtime schema
{ payload: { id: Schema.String } },
);

defineActivity<
"missingError",
{ id: typeof Schema.String },
Schema.Void,
typeof CardDeclined
>(
"missingError",
// @ts-expect-error a non-default error generic requires its runtime schema
{ payload: { id: Schema.String } },
);

// Messages: deferred success, mailbox payload, update request typing.
expectTypeOf<Effect.Success<typeof Approval.await>>().toEqualTypeOf<string>();
expectTypeOf<Effect.Success<typeof Priority.take>>().toEqualTypeOf<{
Expand Down
30 changes: 18 additions & 12 deletions src/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ export type SuccessOf<A> =
export type ErrorOf<A> =
A extends TypedActivity<string, Schema.Top, Schema.Top, infer E> ? E["Type"] : never;

type IsExactly<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;

type ActivityDeclaration<
Payload extends Schema.Struct.Fields | Schema.Top,
Success extends Schema.Top,
Error extends Schema.Top,
> = {
readonly payload: Payload;
readonly options?: TypedActivityOptions;
} & (IsExactly<Success, Schema.Void> extends true
? { readonly success?: Success }
: { readonly success: Success })
& (IsExactly<Error, Schema.Never> extends true
? { readonly error?: Error }
: { readonly error: Error });

/** Build the serializable projection of an activity declaration. */
const makeTypedActivity = <
const Name extends string,
Expand All @@ -141,12 +157,7 @@ const makeTypedActivity = <
Error extends Schema.Top = Schema.Never,
>(
name: Name,
definition: {
readonly payload: Payload;
readonly success?: Success;
readonly error?: Error;
readonly options?: TypedActivityOptions;
},
definition: ActivityDeclaration<Payload, Success, Error>,
): TypedActivity<
Name,
Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
Expand Down Expand Up @@ -319,12 +330,7 @@ export const defineActivity = <
Error extends Schema.Top = Schema.Never,
>(
name: Name,
decl: {
readonly payload: Payload;
readonly success?: Success;
readonly error?: Error;
readonly options?: TypedActivityOptions;
},
decl: ActivityDeclaration<Payload, Success, Error>,
): DefinedActivity<
Name,
Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
Expand Down
Loading