rescript-schema icon indicating copy to clipboard operation
rescript-schema copied to clipboard

Bug with unions: when we use them with optional, null, array, etc., they turn into simple strings

Open fdaciuk opened this issue 8 months ago • 3 comments

if I have a union like this on my schema, the type will be a union:

const schema = S.union(["Win", "Draw", "Loss"])
type Schema = S.Output<typeof schema> // "Win" | "Draw" | "Loss"

That is correct.

But if the type is optional, nullish, array, etc., the union becomes a simple string:

const schema = S.optional(S.union(["Win", "Draw", "Loss"]))
type Schema = S.Output<typeof schema> // string | undefined
const schema = S.nullish(S.union(["Win", "Draw", "Loss"]))
type Schema = S.Output<typeof schema> // string | null | undefined
const schema = S.array(S.union(["Win", "Draw", "Loss"]))
type Schema = S.Output<typeof schema> // string[]

The only way I found to not get this behaviour is using S.schema in any strings of my union:

const schema = S.optional(S.union([S.schema("Win"), S.schema("Draw"), S.schema("Loss")]))
type Schema = S.Output<typeof schema> // "Win" | "Draw" | "Loss" | undefined

Is this a bug or it is the intended behaviour? I'm using [email protected].

fdaciuk avatar Jun 24 '25 19:06 fdaciuk

It might be a TS edge case. I assume it should be possible to fix. Thanks for letting me know. I'm currently on my annual vacation, so I'll take a look in a few weeks. Also, a PR is definitely welcome. All TS types are in the file: https://github.com/DZakh/sury/blob/main/packages/sury/src/S.d.ts and here's a file with TS tests https://github.com/DZakh/sury/blob/main/packages/sury/tests/S_test.ts

DZakh avatar Jun 25 '25 15:06 DZakh

Nice! Enjoy your vacation :heart:

fdaciuk avatar Jun 25 '25 15:06 fdaciuk

Interesting that this also works:

const statuses = S.union(["Win", "Draw", "Loss"]);
const schema = S.optional(statuses);

DZakh avatar Jul 01 '25 09:07 DZakh