`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:
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()
andS.to()
first (but then what if those schemas themselves are transforms?) - Have separate
getFromPropertySignatures
andgetToPropertySignatures
(or something along those lines) that could maybe traverse the AST and recursively resolve Transforms until it hits aTypeLiteral
.