Creating a Generic Tagged Union with Effect and TypeScript

I'm trying to make a generic tagged union to represent values that are to be loaded from an external resource. This is the nongeneric version:
import { Effect as E, Schema as S } from "effect";

type Loadable = typeof Loadable.Type
const Loadable = S.Union(
  S.TaggedStruct("NotStarted", {}),
  S.TaggedStruct("Loading", {}),
  S.TaggedStruct("Loaded", {
    value: S.Union(S.Number, S.String), // How to make this generic?
  }),
);
const [NotStarted, Loading, Loaded] = Loadable.members;

const x = Loaded.make({ value: 1 });
const y = Loaded.make({ value: 'a' });
// const z = Loaded.make({ value: true });  // Currently not allowed

Here is my attempt to make Loaded generic:
import { Match, Schema as S } from "effect";

const NotStarted = S.TaggedStruct("NotStarted", {});
const Loading = S.TaggedStruct("Loading", {});
const Loaded = <T>(schema: S.Schema<T>) =>
  S.TaggedStruct("Loaded", {
    value: schema,
  });

type Loadable<T> =
  | typeof NotStarted.Type
  | typeof Loading.Type
  | {
      _tag: "Loaded";
      value: T;
    };

const Loadable = <T>(schema: S.Schema<T>) =>
  S.Union(NotStarted, Loading, Loaded(schema))

const get = <T>(loadable: Loadable<T>) =>
  Match.value(loadable).pipe(
    Match.tag("Loaded", ({ value }) => value),
    Match.orElse(() => null),
  );

const x = Loaded(S.Int).make({ value: 1 });
const y = Loaded(S.String).make({ value: "a" });
const z = Loaded(S.Boolean).make({ value: true });

// All are correctly inferred
const shouldBeNumberOrNull = get(x);
const shouldBeStringOrNull = get(y);
const shouldBeBooleanOrNull = get(z);

Is there a cleaner way to go about doing this?
Was this page helpful?