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

JSDoc: make it a noImplicitAny error to leave out Array or Promise type argument #32766

Closed
brendankenny opened this issue Aug 8, 2019 · 9 comments

Comments

@brendankenny
Copy link
Contributor

commented Aug 8, 2019

Search Terms

javascript array promise any default type argument

Suggestion

If --noImplicitAny is on, make it an error to leave out the type argument for Array or Promise in JSDoc annotations.

#14284 added support for capitalization aliases commonly found in jsdoc annotations (Number when they meant number) and also made /** @type {Array} an alias for /** @type {Array<any>} and /** @type {Promise} an alias for /** @type {Promise<any>}. From a lot of the jsdoc I've seen, this is probably still the right call (and often exactly what the author meant) when not in a --strict checking environment.

#18778 made it an error to leave out the type argument for generics in JS if noImplicitAny is set, but that doesn't catch Array and Promise because their type is set before getTypeReferenceType can be called and the error found.

It would be great to finish that and always have the type argument warning when noImplicitAny is set.

If this idea sounds ok, I can put up a PR since it looks like a pretty simple change (just fall through getIntendedTypeFromJSDocTypeReference for these types if noImplicitAny is set).

Use Cases

Better alerting of the stealth anys introduced by /** @type {Array} */ and /** @type {Promise} */ to match how e.g. /** @type {Set} */ gives 'Generic type 'Set<T>' requires 1 type argument(s)'.

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code

I guess this may technically be a breaking change (the current behavior was intended by #14284), but since it would be limited to noImplicitAny/strict users and it aligns with #18778's change for all other types, it seems ok?

  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@RyanCavanaugh

This comment has been minimized.

Copy link
Member

commented Aug 9, 2019

@sandersn can you collect data on this when you have a chance?

@sandersn

This comment has been minimized.

Copy link
Member

commented Aug 9, 2019

A few things:

  1. #18778 only errors on extends and @extends. We still fill in type arguments with any everywhere but @extends in JSDoc.
  2. Probably the right thing is to disable this for all types with noImplicitAny on.
  3. I'm not sure what the data collection question is here. How many checkJs+noImplicitAny projects will we break? How much higher would the barrier be for checkJs projects to add noImplicitAny? Something else?

@brendankenny for (1) and (2)
@RyanCavanaugh for (2) and (3)

@sandersn

This comment has been minimized.

Copy link
Member

commented Aug 9, 2019

The any-filling behaviour in JS probably means that getIntendedTypeFromJSDocTypeReference can skip the type arguments check and return arrayType instead of anyArrayType, for example. That would not change the current semantics, I think.

It might need to interact with its parent, getTypeFromTypeReference, to correctly instantiate arrays and promises, making it a bit more complicated.

@brendankenny

This comment has been minimized.

Copy link
Contributor Author

commented Aug 9, 2019

A few things:
2. Probably the right thing is to disable this for all types with noImplicitAny on.

I might not have been precise enough with my suggestion. I was only suggesting fixing the explicit-jsdoc-type case, e.g.

// @noImplicitAny: true

/** @type {Array} */ // Array<any>, no error
const arr = [];

which is already an error for most parameterized types, like

// @noImplicitAny: true

/** @type {Set} */ // error: Generic type 'Set<T>' requires 1 type argument(s)
const set = new Set();

un-annotated code is happy to go with any:

// @noImplicitAny: true

const set = new Set(); // Happily Set<any> with no error

which it seems might be what you're referring to here? That would be amazing to start erroring (I guess with a similar suggestion in an error message as the @augments one, but for @type) but that's a lot larger scale change than I had considered :)

edit: actually I see now that any comes from the SetConstructor declaration so maybe I'll stop trying to guess what you meant :)

  1. #18778 only errors on extends and @extends. We still fill in type arguments with any everywhere but @extends in JSDoc.

Hopefully this reference makes more sense after limiting the scope above. It looks like it was a side effect of adding the extends check in #18778? It's from the fallback condition in getTypeFromClassOrInterfaceReference if there are missing type arguments and missingAugmentsTag is false (the error goes to Diagnostics.Generic_type_0_requires_1_type_argument_s or Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments).

@brendankenny

This comment has been minimized.

Copy link
Contributor Author

commented Aug 9, 2019

That would be amazing to start erroring but that's a lot larger scale change than I had considered

for reference, I was looking at something as simple as https://github.com/microsoft/TypeScript/compare/master...brendankenny:e00d71f?expand=1 (#32829)
(with apologies for growing those ternaries...I could change them if needed :)

That commit also removes the no-argument Object to any default for noImplicitAny as well, which seemed reasonable.

That Object change is the only cause of baseline changes in two files and the changes seemed (hopefully) independent of what was being tested in them.

@sandersn sandersn changed the title JS: make it a noImplicitAny error to leave out Array or Promise type argument JSDoc: make it a noImplicitAny error to leave out Array or Promise type argument Aug 12, 2019

@sandersn

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

@brendankenny I think you were precise enough, I just mis-remembered the rules for jsdoc types. =)

This seems like a good idea -- ideally Array and Promise would behave the same as other types, we just need to make them lenient in the default case.

Removing the Object -> any mapping is a much bigger deal, although still probably a good idea.

Now that I understand the bug, I think the main interesting data collection question is how many tsconfigs in the world have both checkJS and strict turned on. Both of these changes are breaking for these tsconfigs, but probably in a good way.

@brendankenny

This comment has been minimized.

Copy link
Contributor Author

commented Aug 12, 2019

I think the main interesting data collection question is how many tsconfigs in the world have both checkJS and strict turned on. Both of these changes are breaking for these tsconfigs, but probably in a good way.

Would the next step be to open a PR and decide the question there or to decide it first before opening a change?

@sandersn

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

Either one is fine with me. I don't think the number is very high, but I haven't come up with a way to estimate the number yet either.

@sandersn

This comment has been minimized.

Copy link
Member

commented Aug 14, 2019

I sampled some npm packages and looked at their github repos for tsconfig or jsconfig at the root. Of almost 5000 repos, this turned up 250 tsconfigs and 5 jsconfigs. Of those, half had strict or noImplicitAny on, 13 had allowJs on, and 3 had checkJS on. Only 5 had allowJs+strict/noImplicitAny and none of the 3 checkJs projects had strict on.

I'm still sampling, but I think that means we can do whatever we want with strict+checkJs since so few people are using it right now.

@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Aug 16, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.