Issue with Merging Transformed Structs in Effect Typescript

I thought I could merge a Struct generated with Schema.transform with another using Schema.extend, but I can't get it to work.

I am trying to map {fallback: 0|1, ...rest} to {fallback?: true, ...rest}.

I defined a fallback Struct which can either be {} or {fallback: true} (this part behaves as expected)
const fallback = S.transform(
    S.Struct({ fallback: S.Union(S.Literal(0), S.Literal(1)) }),
    S.Union(S.Struct({ fallback: S.Literal(true) }), S.Struct({})),
    {
        strict: true,
        decode: a => a.fallback === 1 ? { fallback: true } : {},
        encode: a => ({ fallback: 'fallback' in a && a.fallback ? 1 : 0 } as const)
    }
);

Then I tried to merge it with another Struct containing the rest of my fields:
const ContentListItem = S.extend(
    S.Struct({ id, type, ordering, published, title, slug }),
    fallback,
);

However, I get a runtime error:
Unsupported schema or overlapping types
cannot extend { readonly id: number; readonly type: "lesson" | "playground"; readonly ordering: number; readonly published: BooleanFromUnknown; readonly title: string; readonly slug: string } with with ({ readonly fallback: 0 | 1 } <-> { readonly fallback: true } | {})

An alternate, simpler, design is the following, but there are several things I don't like about it:

- Encoded will give me {fallback?: 1 | 0 | undefined, ...rest} which is not correct
- S.decodeUnknown will output {fallback: undefined, ...rest} instead of omitting fallback when it is 0, which can't be converted to JSON.

const fallback = S.transform(
    S.Union(S.Literal(0), S.Literal(1)),
    S.Union(S.Literal(true), S.Undefined), 
    {
        strict: true,
        decode: a => a === 1 ? true : undefined,
        encode: a => a ? 1 : 0,
    }
);

const ContentListItem = S.Struct({
    id, type, ordering, published, title, slug,
    fallback: S.optional(fallback)
});


What do you think?
Was this page helpful?