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: improve populate type narrowing #11503

Merged
merged 8 commits into from Mar 11, 2022

Conversation

mohammad0-0ahmad
Copy link
Contributor

Should resolve #11496
@Uzlopak

@Uzlopak
Copy link
Collaborator

Uzlopak commented Mar 8, 2022

This one is better.

types/index.d.ts Outdated
@@ -1813,7 +1813,8 @@ declare module 'mongoose' {

type QueryWithHelpers<ResultType, DocType, THelpers = {}, RawDocType = DocType> = Query<ResultType, DocType, THelpers, RawDocType> & THelpers;

type UnpackedIntersection<T, U> = T extends (infer V)[] ? (V & U)[] : T & U;
type UnpackedIntersection<T, U> = T extends (infer A)[] ? (A & U)[] : keyof U extends never ? T & U: { [P in keyof U]: U[P] extends (infer B)[] ? (B & T)[] : U[P] & T };
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't the last bit be something like T[P] & U[P]? I think T should come first, and then we should be merging T's keys as well as opposed to merging T into U's keys.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check the new commit


Users.findOne({}).populate<{friends: Friend[]}>('friends').then(user => {
expectAssignable<Friend | undefined>(user?.friends[0]);
user?.friends[0].blocked;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we do expectType<boolean> here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

So is it now fixed?

@@ -1813,8 +1813,11 @@ declare module 'mongoose' {

type QueryWithHelpers<ResultType, DocType, THelpers = {}, RawDocType = DocType> = Query<ResultType, DocType, THelpers, RawDocType> & THelpers;

type UnpackedIntersection<T, U> = T extends (infer V)[] ? (V & U)[] : T & U;
type UnpackedIntersectionWithNull<T, U> = T extends null ? UnpackedIntersection<T, U> | null : UnpackedIntersection<T, U>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we really need UnpackedIntersectionWithNull type?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We introduced UnpackedIntersectionWithNull to fix #11041. Although it looks like the test for that issue still passes with this change, so looks like we don't need it after all.

types/index.d.ts Outdated
? (Omit<A, keyof U> & U)[]
: keyof U extends never
? T
: Omit<T, keyof U> & { [P in keyof U]: U[P] extends (infer B)[] ? (HydratedDocument<B> & B)[] : HydratedDocument<U[P]> & U[P]};
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've added HydratedDocument To populated property, is that correct? Else tests at line will fail at lines mentioned with #HydratedDocument.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well hmm, actually the thing is, that it is only a HydratedDocument if in populate the option lean is set to false or lean() is used on the query builder. So I suspect this is wrong :/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, I will refact that in the next commit :)

Copy link
Collaborator

@Uzlopak Uzlopak Mar 11, 2022

Choose a reason for hiding this comment

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

@mohammad0-0ahmad
Imho, if you cant fix that than I would actually recommend to remove those expectTypes, which vkarpov15 requested and revert those HydratedDocument changes, if this is a hard case to solve for you. (Not suggesting that this is over your skills). Probably this is happening because tsd uses a different typescript version and thus resulting in some issues which dont happen with latest typescript, which is used in vscode for their intellisense. So this is maybe some kind of scope creep. It was not even originally a task for you. So I actually dont want that you feel forced to solve this issue.

But if you think this is a nice challenge and you really want to supply an A-Grade solution, than feel free to invest more time and energy. And know that your work is atleast by me appreciated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your words, no worries it was funny actually at the beginning I though that as well but it's works now.

@mohammad0-0ahmad
Copy link
Contributor Author

I've refacted this & it should work with both VSC intellisense & tsd.

populate<Paths = {}>(path: string, select?: string | any, model?: string | Model<any, THelpers>, match?: any): QueryWithHelpers<UnpackedIntersectionWithNull<ResultType, Paths>, DocType, THelpers, RawDocType>;
populate<Paths = {}>(options: PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<UnpackedIntersectionWithNull<ResultType, Paths>, DocType, THelpers, RawDocType>;
populate<Paths = {}>(path: string, select?: string | any, model?: string | Model<any, THelpers>, match?: any): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;
populate<Paths = {}>(options: PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;
Copy link
Collaborator

@Uzlopak Uzlopak Mar 11, 2022

Choose a reason for hiding this comment

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

In #11518 we got a regression reported.

Suggested change
populate<Paths = {}>(options: PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;
populate<Paths = {}>(options: string[] | PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;

Corresponding typing test would be:

async function gh11518() {
  // populate should accept an Array with the populated paths
  await Story.findOne().populate(["author"]);
}

If you want, we can do this in this PR. If not, I can create a PR. I just didnt wanted to create a PR before this is merged to avoid high probable merge conflict.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@vkarpov15 Only the second populate type can handle string arrays correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OR maybe only the first one?

Copy link
Collaborator

Choose a reason for hiding this comment

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

lets wait for feedback by vkarpov

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's an independent issue that I fixed in #11518, no need to discuss that in this PR. But yes, you can call both syntaxes with an array of paths.

Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

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

Thanks!

@vkarpov15 vkarpov15 merged commit 7ce083d into Automattic:master Mar 11, 2022
vkarpov15 added a commit that referenced this pull request Mar 11, 2022
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.

Typescript Populate Issue
3 participants