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(core): type definition of Dataset.reduce #2774

Merged
merged 9 commits into from
Dec 21, 2024
Merged

Conversation

halvko
Copy link
Contributor

@halvko halvko commented Dec 16, 2024

Fixes #2773

I'm seeing type errors and test failures in ./test/core/sitemap_request_list.test.ts both before and after my change.

This PR currently doesn't add tests to check that types resolve correctly. In the reduce() uses first value as memo if no memo is provided test, the result from reduce was previously inferred to be any, and is now inferred to be Dictionary. Adding a type annotation doesn't help catch this change as implicit any is allowed.

@halvko halvko changed the title Fix type definition of Dataset.reduce fix(core): type definition of Dataset.reduce Dec 16, 2024
@halvko
Copy link
Contributor Author

halvko commented Dec 16, 2024

Idk how the bad main signature slipped past me, but it's fixed now

@B4nan B4nan requested a review from vladfrangu December 17, 2024 12:05
@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

The type errors are caused by missing import in that test

-import { SitemapRequestList } from '@crawlee/core';
+import { SitemapRequestList, type Request } from '@crawlee/core';

I'll adjust the CI so it fails when there are type errors in the tests, I thought we already do that, but apparently not 🙃

@halvko
Copy link
Contributor Author

halvko commented Dec 17, 2024 via email

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

Yeah I can do that now, I hope there won't be more type issues in the tests :D

@halvko
Copy link
Contributor Author

halvko commented Dec 17, 2024

Fixed the eslint errors. I question if it makes sense to separate overload signatures with newlines, but I've done it.

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

You also need to duplicate the jsdoc on all the overloads, otherwise it wont be part of the generated API docs.

This part sucks hard I its the main reason why I always try to not use overloads in the first place 🙃

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

Yeah I can do that now, I hope there won't be more type issues in the tests :D

This might take some time, there were a few errors and one of them was caused by the fact that we had strictNullChecks disabled for tests, and enabling that yields 300+ errors :D

@halvko
Copy link
Contributor Author

halvko commented Dec 17, 2024

When I have fixed the documentation on this, would it be possible to merge before fixing all of the current test issues? It's not this change introducing the problems, right?

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

As long as the CI is passing, sure. But I will most likely finish this during the afternoon, I just need to add a lot of ! in the tests.

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

I wonder if we really need the overloads, why can't we just mark the second parameter as optional?

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

Btw we actually do have an existing test for the reduce method, but because of the disabled strictNullChecks in tests, it was passing just fine on type-level too. And I can see the inference is completely broken too, for both cases, and it feels like the overloads are not helping with that either, I think we will need to use NoInfer in them.

@halvko
Copy link
Contributor Author

halvko commented Dec 17, 2024 via email

@halvko
Copy link
Contributor Author

halvko commented Dec 17, 2024 via email

@B4nan
Copy link
Member

B4nan commented Dec 17, 2024

The checks are enabled here #2776, I've added some @ts-expect-error comments with a FIXME to the dataset tests. Once merged, please rebase and try to get rid of them ideally. If you struggle, we can take over with that part.

Erik Funder Carstensen added 7 commits December 21, 2024 17:04
BREAKING CHANGE: Dataset.request return type now correctly reflects that `undefined` may be returned
if called on an empty Dataset without the `memo` argument. As calling it without a `memo` argument
already lead to an errorinous type error, users probably already have type casts around it in this
situation, but if not, the new case can be ignored by asserting that there will be a value.

Before:

const res = dataset.reduce(
    async (memo, item, index) => {
        // example impl
        return item;
    }
);

After:

const res = dataset.reduce(
    async (memo, item, index) => {
        // example impl
        return item;
    }
)!;

Note that the original snippet was already rejected by TypeScript for calling reduce with too few
arguments. The workaround to this was to pass `undefined` as the second argument, making
TypeScript infer the type of `res` as `undefined`. This can be "fixed" in one of two ways:
1. In the DatasetReducer, casting the memo argument and the result of reduce to `Data`.
   - In this case no change is neccesary to the user code
2. Calling reduce with the memo argument `undefined as Data`
   - In this case the migration is neccesary
return memo.concat(item);
},
[],
new Array(),
Copy link
Member

Choose a reason for hiding this comment

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

this is actually fixing something? how is [] different from new Array()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, this should have gone here: #2774 (comment)

@halvko
Copy link
Contributor Author

halvko commented Dec 21, 2024 via email

@B4nan
Copy link
Member

B4nan commented Dec 21, 2024

Ok, I thought it will be something like that.

I didn’t check if type annotating the return value would also fix the issue.

Mostly likely yes. Since we disallow array constructor in eslint, it would be a better solution than adding eslint ignore comments.

@halvko
Copy link
Contributor Author

halvko commented Dec 21, 2024

I didn’t check if type annotating the return value would also fix the issue.

It didn't - we can instead solve it by doing a type cast on the input memo

@halvko
Copy link
Contributor Author

halvko commented Dec 21, 2024

This smells of either bad API design or type definition but it should be noted that Array.prototype.reduce has the same issue: Playground

@B4nan
Copy link
Member

B4nan commented Dec 21, 2024

Yeah, I just wanted to point out the same, you are the one to provide a correct type in the initializer, just like in the array method. TS will see [] as an empty array, represented by never[]. I don't think we can do much about that.

@B4nan B4nan merged commit 59bc6d1 into apify:master Dec 21, 2024
9 checks passed
@B4nan
Copy link
Member

B4nan commented Dec 21, 2024

All green, thanks!

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.

Type definition on Dataset.reduce does not match documented (and implemented) behaviour
3 participants