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: no longer removing Map or Set type when they are needed #1520

Merged

Conversation

rubiesonthesky
Copy link
Collaborator

PR Checklist

Overview

I'm not sure that this is correct place to place this code. It's also maybe too heavy handed. But on the other hand, I think it's better to prevent cases where we introduce implicit anys when there was some type earlier. Keeping types that could have been removed, is less bad in that case.

I have tried to find what would be right place to do this check but I did not have any luck.

@rubiesonthesky rubiesonthesky force-pushed the fix-for-removing-map-type branch from 6a6c5ae to 0d3d550 Compare April 3, 2024 19:03
Copy link

codecov bot commented Apr 3, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 78.68%. Comparing base (e484ffc) to head (47a9292).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1520      +/-   ##
==========================================
+ Coverage   78.62%   78.68%   +0.05%     
==========================================
  Files         175      175              
  Lines       10957    10968      +11     
  Branches     1021     1026       +5     
==========================================
+ Hits         8615     8630      +15     
+ Misses       2338     2334       -4     
  Partials        4        4              
Flag Coverage Δ
mutation 73.31% <100.00%> (+0.06%) ⬆️
unit 28.34% <0.00%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Owner

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

I think this is a good start but there are some tricky edge cases that I worry might make this a lot more complex than it seems. Good luck! ✨

src/shared/comparisons.ts Outdated Show resolved Hide resolved
Copy link
Owner

Choose a reason for hiding this comment

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

[Testing] A few more cases come to mind...

  • let stringMapTyped: Map<string, string | number> = new Map<string, number>();: should keep the type annotation, I think?
  • ReadonlyMap
  • Custom generic classes like class MyMap<K, V> { ... }
  • type aliases

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice! thanks. And I agree this is more complex, I just touched surface. 😅

@JoshuaKGoldberg JoshuaKGoldberg added the status: waiting for author Needs an action taken by the original poster label Apr 9, 2024
@rubiesonthesky
Copy link
Collaborator Author

Comparing ts.Types of code like this const stringSet: Set<string> = new Set(); does not work. Both sides have same type arguments. But if we compare the actual nodes and their type arguments, then we can find differences. In most cases, you want to compare the types typeChecker has inferred for you, but this seems special case in that regard.

If you look this tool https://ts-ast-viewer.com/#code/MYewdgzgLgBNBOBLMBzAygUygLhpqAPAsigHwwC8MYGA7nlgBQCUA3EA and then compare the inferred type of NewExpression and TypeReference, you can see that both have Set<string>. And that is where this bug comes from.

For Map this is different. Same comparisation in that tool tells us that the types are Map<string, string> and Map<any, any>.

case "RegExp":
return initializer.kind === ts.SyntaxKind.RegularExpressionLiteral;
}
if (ts.isRegularExpressionLiteral(declaration)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is not related to the issue, but I think it's easier to read and understand this way.

Copy link
Owner

Choose a reason for hiding this comment

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

No preference on my end 😄

return false;
}

for (let i = 0; i < declarationTypeArguments.length; i += 1) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There should be only one type argument in Set, but I copied this code from above.


export const declaredInitializedTypeNodeIsRedundant = (
request: FileMutationsRequest,
declaration: ts.TypeNode,
initializer: ts.Node,
) => {
): boolean | undefined => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wonder should this method always return boolean? From the usage, it's always used in if check, so it does not really matter that it also returns undefined. But on the other hand, it could return false in those cases.

Copy link
Owner

Choose a reason for hiding this comment

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

🤷 I don't have a hard preference either way 😄

>();
const stringMapTyped = new Map<string, number>();
const anyMap = new Map();
const anySet: Set<any> = new Set();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This could lose it's type declaration. But I think it would need it's own custom logic for this special case.

@rubiesonthesky
Copy link
Collaborator Author

I added isTypeBuiltIn check for Map, Set and Readonly. I'm not totally sure why it would matter here, but I guess it can be a safe guard in future.

Copy link
Owner

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

Looks great to me, thanks!

I've context switched away from TypeStat for a bit to focus on ESLint stuff. Sorry that reviewing is taking a while. But I'm still very excited you're looking at all this! 🙌

@JoshuaKGoldberg JoshuaKGoldberg removed the status: waiting for author Needs an action taken by the original poster label Apr 23, 2024
@JoshuaKGoldberg JoshuaKGoldberg merged commit d27679b into JoshuaKGoldberg:main Apr 23, 2024
11 checks passed
@rubiesonthesky rubiesonthesky deleted the fix-for-removing-map-type branch May 4, 2024 16:27
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.

🐛 Bug: noInferableTypes removes incorrectly type from Map variable
2 participants