Skip to content

Infer typedef variable declaration to never #36454

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

Closed
wants to merge 1 commit into from

Conversation

TimvdLippe
Copy link
Contributor

Typedefs have two forms: specify a name in the @typedef declaration or
use the name of the variable declaration it is attached to. Since
@typedef types should only live in the type space, any reference to a
variable that has a @typedef attached to is illegal. As such, assign
it the never type if the @typedef itself does not specify a name.

Fixes #36375

Typedefs have two forms: specify a name in the `@typedef` declaration or
use the name of the variable declaration it is attached to. Since
`@typedef` types should only live in the type space, any reference to a
variable that has a `@typedef` attached to is illegal. As such, assign
it the `never` type if the `@typedef` itself does not specify a name.

Fixes microsoft#36375
Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

A couple of comments on the code.

Also, I don't know how valuable this is. Its value is based on the number of closure projects that are going to migrate directly to "noImplicitAny": true. Any idea how many that would be? (I assume that they're all inside google.)

// The typedef is attached to a variable declaration, instead of specifying the name in the typedef itself
// This means that the variable declared references the typedef and should not be used in regular control
// flow of the program, only in jsdoc type references.
if (jsDocTypeDefTag && !jsDocTypeDefTag.name && isVariableDeclaration(declaration)) {
Copy link
Member

Choose a reason for hiding this comment

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

probably need to check that there is no initialiser too

Copy link
Member

Choose a reason for hiding this comment

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

oh, and isInJSFile, no exports, not a binding pattern, not a declare (which is illegal in js, but might show up anyway).

if (jsDocTypeDefTag && !jsDocTypeDefTag.name && isVariableDeclaration(declaration)) {
return neverType;
}

if ((noImplicitAny || isInJSFile(declaration)) &&
Copy link
Member

Choose a reason for hiding this comment

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

Actually, maybe the new code should be moved inside here.

@TimvdLippe
Copy link
Contributor Author

Yesterday, I realized that noImplicitAny was only pointing out the root problem. TS allowed references to @typedef variable declarations in value space rather than type space. I think that is a bug that warrants fixing (which is this PR). That said, noImplicitAny is one of the main reasons we are migrating to TS. I guess we could roll a fork during our migration (which is expected to take months/years), but I would rather fix it upstream 😄

I will process your code review tomorrow, thanks for taking a look!

@ahejlsberg
Copy link
Member

I'm not crazy about the use of type never for the variable (recall, never is assignable to anything). The never type is supposed to represent values that never exist, but clearly the variable does. I think it would be better to use type undefined and verify that the variable has no initializer. That would then reflect the true type of the variable and would ensure nothing other than undefined is assignable to it.

@sandersn
Copy link
Member

sandersn commented Jan 28, 2020

@ahejlsberg the intent is to prevent using the type alias variable as an assignment source, so never would be better.

But probably the correct fix is to give an error whenever the variable is referenced in a value position and then suppress the implicit any error. Then the type can remain any.

Edit: Since closure verifies that there is no initialiser, I wouldn't bother making Typescript give an error; just treat it like a normal declaration:

/** @typedef {number} */
var Typename = 12; // value references to Typename should be fine

@ahejlsberg
Copy link
Member

the intent is to prevent using the type alias variable as an assignment source, so never would be better

You mean assignment target, yes? If you give it type never it can be used as an assignment source for anything.

What exactly are we trying to prevent? Reads of the variable, writes to the variable, or both?

@sandersn
Copy link
Member

Yep, I got it backwards. never is wrong.

We're trying to prevent both reads and writes of the variable since it's only there so Closure can have a name for the associated type alias. I think an error on value-space usage of the variable is better than changing the type, plus suppression of the implicit any error.

@TimvdLippe
Copy link
Contributor Author

@sandersn Shall I close this in favor of #28162 ?

@sandersn
Copy link
Member

sandersn commented Feb 3, 2020

Yes, I think that's the right path forward.

@TimvdLippe TimvdLippe closed this Feb 3, 2020
@TimvdLippe TimvdLippe deleted the typedef-never branch February 3, 2020 22:07
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.

Nameless @typedef has implicit any error on the associated identifier
3 participants