Effect-TS / schema

Modeling the schema of data structures as first-class values

Home Page:https://effect.website

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`S.getPropertySignatures` does not play nicely with `withDefault()`

mkrause opened this issue Β· comments

πŸ› Bug report

Current Behavior

Take the following snippet:

const Test = S.struct({
  foo: S.optional(S.string).withDefault(() => ''),
});
S.getPropertySignatures(Test);

This produces a type error as in the following screenshot:

Screenshot 2023-05-08 at 15 20 47

It looks like this is because getPropertySignatures assumes I extends from A with all properties required, whereas with withDefault() the property becomes optional in I.

export declare const getPropertySignatures: <I extends { [K in keyof A]: any; }, A>(schema: Schema<I, A>) => { [K_1 in keyof A]: Schema<I[K_1], A[K_1]>; };

Expected behavior

Would expect getPropertySignatures not to throw a type error in this case.

Suggested solution(s)

If we change the type of getPropertySignatures to extend from { [K in keyof A]?: any; } instead, this seems to work:

export declare const getPropertySignatures: <I extends { [K in keyof A]?: any; }, A>(
  schema: Schema<I, A>
) => { [K_1 in keyof A]-?: Schema<I[K_1], A[K_1]>; };

Also had to change the return type to include -? otherwise the result will have all properties as optional.

Software Version(s)
@effect/schema v0.17.2
TypeScript v5.0.4

Ah, never mind. I just figured out that S.getPropertySignatures does not work with transforms at all currently. That's kind of unfortunate. Would it be possible to make this work with useDefault()?

getPropertySignatures was added when Schema<A> only had one parameter (7259743), I don't think it makes sense anymore now that a schema has two parameters (Schema<I, A>) and can describe transformations that involve the entire struct and not just the values of some keys (such as optional fields with default values). Its name is also misleading (you get a struct of schemas, not a struct of property signatures). For all these reasons, I believe that it's better to remove it in the next release.

Thanks for the response, I closed this issue.

I agree the current implementation of getPropertySignatures doesn't really make sense anymore. I think it would still be useful to have a mechanism to get a property signature for a schema. Ideally it would return an S.PropertySignature. But this becomes tricky with withDefault() currently because the fact that something was defined with a default seems to be essentially lost in the transformation. I wonder if it would be useful to keep the original withDefault function around somehow, maybe as an annotation.

Another issue (as you mentioned) is the fact that each schema may now have two sets of property signatures: the "to" and "from" signatures. I see a few possible solutions:

  • Always choose the "to" type (basically what happens now)
  • Have the user use S.from() and S.to() first (but then what if those schemas themselves are transforms?)
  • Have separate getFromPropertySignatures and getToPropertySignatures (or something along those lines) that could maybe traverse the AST and recursively resolve Transforms until it hits a TypeLiteral.