Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ObjectSchemaOf type definition #1170

Merged
merged 1 commit into from
Jan 11, 2021

Conversation

chasecaleb
Copy link
Contributor

Follow up to #1169, because in my haste to rebase I overlooked adding Lazy to the ArraySchema generic in ObjectSchemaOf. I also simplified the ObjectSchemaOf definition since it doesn't need to repeat the SchemaOf definition. I also fixed my incorrect formatting from #1169.

I've tested this against my own project via yarn link so I know it at least works for my use cases.

@jquense
Copy link
Owner

jquense commented Dec 10, 2020

I actually don't think you want to add the Lazy here. What is the use case?

@chasecaleb
Copy link
Contributor Author

Something like this, where the snippet below is used for a field in a Yup.object() validator

Yup.array(
        Yup.lazy<YupSchema<ModuleData>>(element => {
            // ... dynamic logic here
        })
    );

@chasecaleb
Copy link
Contributor Author

BTW, #1169 already added Lazy to the ArraySchema generic within SchemaOf. This PR just makes it consistent within ObjectSchemaOf as well.

@jquense
Copy link
Owner

jquense commented Dec 11, 2020

yeah i see. hmm I am a bit concerned that this will break other common cases like #1155

It probably makes sense to have a common interface shared between lazy and schema (there is already one simple one) but unsure if that would break other stuff...

@chasecaleb
Copy link
Contributor Author

I don't think it breaks that use case, does it? Changing the type definition to add Lazy to the top level like SchemaOf<T> = Lazy<T> | ...the rest would cause issues, but that's not what I'm proposing here. The only part I'm adding Lazy to is inside ArraySchema<SchemaOf<E> | Lazy<SchemaOf<E>>>, not at the top level. So you would still be calling validate() on the ArraySchema type, which the inner generic part shouldn't affect.

@jquense
Copy link
Owner

jquense commented Dec 11, 2020

yeah that's true for this specific change, but technically it's an incomplete change, since object properties also accept Lazy

so you fix your example above but this still doesn't work i think?

type Person {
   name: string
}

const s: SchemaOf<Person> = object({ name: lazy(() => string().defined() })

src/index.ts Outdated Show resolved Hide resolved
@chasecaleb
Copy link
Contributor Author

Okay, I just committed the ObjectSchemaOf addition. How's it look now?

src/index.ts Outdated
? // we can't use ObjectSchema<{ []: SchemaOf<T[k]> }> b/c TS produces a union of two schema
ObjectSchemaOf<T[k]>
: BaseSchema<Maybe<T[k]>, AnyObject, T[k]>;
[k in keyof T]-?: SchemaOf<T[k]> | Lazy<SchemaOf<T[k]>>;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the old comment here. We can't use SchemaOf<T[k]> because of how TS applies the types over the conditional in SchemaOf. Basically if the input type is something like string | undefined, you get SchemaOf<string> | SchemaOf<undefined>, not SchemaOf<string | undefined>, The behavior is different for passing the generic to a concrete type like BaseSchema. Just means some duplication

Copy link
Contributor Author

@chasecaleb chasecaleb Dec 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay... I'm really confused about what's going on here (and I've been playing with it for two hours now). Either I'm doing something wrong, or it seems like that comment is backwards. Can you look at the minimal example I made in this commit? 8bf7689

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I somewhat suspect the issue is with my example code (FormData/buildNestedValidator), not the Yup type definitions... but I can't figure out the right way, either. I'm not sure how to translate my recursive FormData to a corresponding SchemaOf type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ha, I think I figured out what's going on. I'll get back to you soon with this sorted out. Recursive types are... fun.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I added a commit that adds lazy to field values for object schemas.

And in case you wanted an explanation on how I got so confused:

interface FormData {
  [K: string]: string | FormData;
}
type FormDataSchema = ObjectSchema<{
  [K: string]: SchemaOf<string> | FormDataSchema;
}>;
export const buildNestedValidator = (
  path: string[],
  validator: SchemaOf<string> | FormDataSchema,
): FormDataSchema => {
  const [head, ...rest] = path;
  const result: SchemaOf<string> | FormDataSchema =
    rest.length === 0 ? validator : buildNestedValidator(rest, validator);
  return objectCreate({ [head]: result });
};
const foo: FormData = { foo: '', bar: { baz: '' } };
const val = buildNestedValidator(['bar', 'baz'], stringCreate().required());
val.validate(foo);

I was trying to use SchemaOf<FormData> originally, but that wasn't working. The solution was to create the FormDataSchema type and use it instead. I think that's because of how the union gets distributed - e.g. SchemaOf<string | string[]> vs SchemaOf<string> | SchemaOf<string[]. Something along those lines - my brain hurts at the moment.

Anyways, that's all irrelevant to the actual change in this PR and is just context on how I got so tripped up testing against my own code base. I went ahead and rebased to squash my mess - this is ready for you to review and potentially merge now.

@chasecaleb
Copy link
Contributor Author

Hi, any thoughts on the current state of this MR?

@jquense
Copy link
Owner

jquense commented Dec 29, 2020

will get back to you next week, on vacation!

@chasecaleb
Copy link
Contributor Author

@jquense quick reminder about this PR. Hope you had a good vacation, too!

@jquense jquense merged commit 3b67dc0 into jquense:master Jan 11, 2021
@chasecaleb chasecaleb deleted the fix-schemaof-type branch January 13, 2021 22:45
@chasecaleb
Copy link
Contributor Author

Thanks for working with me on this PR and merging it!

Do you have plans to make a new release with this change? It would help me out when you get a chance so that I can get rid of some temporary workaround code, but it isn't urgent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants