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 @enum with import/export #33575

Closed
art-in opened this issue Sep 24, 2019 · 14 comments · Fixed by #39955
Closed

jsdoc @enum with import/export #33575

art-in opened this issue Sep 24, 2019 · 14 comments · Fixed by #39955
Assignees
Labels
Bug A bug in TypeScript Domain: JSDoc Relates to JSDoc parsing and type generation Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@art-in
Copy link

art-in commented Sep 24, 2019

TypeScript Version: 3.6.3

Code

This works:

/** @enum {number} */
const MyEnum = {
  a: 1,
  b: 2
};

/** @type {MyEnum} */
const v = MyEnum.b;

This doesn't work (MyEnum imported from separate file):

// my-enum.js

/** @enum {number} */
const MyEnum = {
  a: 1,
  b: 2
};

export default MyEnum;

// main.js

import MyEnum from './my-enum.js';

/** @type {MyEnum} */ // ERROR: 'MyEnum' refers to a value, but is being used as a type here. ts(2749)
const v = MyEnum.b;

Expected behavior:

No type errors.

It did work fine in v2.8.3

@nickpelone
Copy link

nickpelone commented Sep 24, 2019

I have the inverse of this issue, where I can't do something like:

import {MyEnum} from './my-enum.js';

const foo = MyEnum.a; // "'MyEnum' only refers to a type, but is being used as a value here"
const bar = MyEnum['b']; // Same thing

switch(baz) {
  case MyEnum.a: // and also here
    console.log("xyz");
    break;
  case MyEnum.b: //and here
    break;
  default:
}

It used to work as of TypeScript 3.5.3, I discovered this issue when upgrading a project this morning.

@ahocevar
Copy link

I can confirm that 3.5.3 was the last version where @art-in's scenario worked. We are having the same issue in OpenLayers.

What still works is this:

// main.js

import MyEnum from './my-enum.js';

/** @type {import("./my-enum.js").default} */ // No error
const v = MyEnum.b;

But that's a bit cumbersome, considering that we have MyEnum imported already.

@wulfsberg
Copy link

Given that 3.7 has the game-changing #7546, I would be very sad to not be able to use it because of this.

@sandersn
Copy link
Member

sandersn commented Oct 16, 2019

#34515 appears to improve the situation -- it resolves a type -- but it resolves the wrong type. MyEnum resolves to { [s: string]: number } not number as it should be.

The problem is that the imported MyEnum is marked as BlockScopedVariable, not TypeAlias. So it incorrectly falls through the type alias case and uses the jsdoc code path that treats values as types. This is not the right code path (I think) even though it now returns a type.

I think the fix is to resolve the alias symbol for MyEnum correctly.

@ahocevar
Copy link

I can confirm that #34515 does not fix the issue. The error is now

Argument of type 'number' is not assignable to parameter of type '{ a: number; b: number; }

@sandersn Is there anything I can help with to get this resovled?

@sandersn
Copy link
Member

sandersn commented Dec 5, 2019

I believe @elibarzilay is looking at the alias resolution code right now in order to fix the symbol's flags. I hope it's an overlooked code path and not something deep in alias resolution.

@ahocevar
Copy link

I just tried v3.8.1-rc, but this is still broken. Has there been any progress?

@ahocevar
Copy link

Thanks everyone for the great work recently on JSDoc support, which allows us to publish auto-generated .d.ts files from our JSDoc annotated JavaScript code base. That's awesome!

This one is the last blocker for TypeScript being 100% useful with JSDoc annotations. Is there a new milestone for this? It is still broken in v3.9.0-dev.

@ahocevar
Copy link

ahocevar commented Mar 11, 2020

The problem boils down to this:

Assume you have the following my-enum.js file:

/** @enum {number} */
const MyEnum = {
  a: 1,
  b: 2
};

export default MyEnum;

Now when you import the enum in a different file, the following will work:

import MyEnum from './my-enum.js';

/** @type {import("./my-enum.js").default} */
const v = MyEnum.b;

The follwoing will cause the reported error:

import MyEnum from './my-enum.js';

/** @type {MyEnum} */
const v = MyEnum.b;

I believe this is because MyEnum is also used as an object literal here, so the type is resolved differently. The above is equivalent to this, which triggers the same error:

import MyEnum from './my-enum.js';

/** @type {typeof MyEnum} */
const v = MyEnum.b;

@evmar
Copy link
Contributor

evmar commented May 5, 2020

Resummarizing this bug, you cannot import a value marked with @enum. This regressed in TypeScript 3.6.

/** @enum {string} */
const x = { a: 'b' };
export {x};

// new file:
import {x} from './otherfile.js';
x.a;  // ERROR

workaround is to write export const instead of the separate export.

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label May 20, 2020
@elibarzilay
Copy link
Contributor

Quick note: the /** @type {import("./my-enum.js").default} */ case is broken too -- it gets a type of any.

@ahocevar
Copy link

ahocevar commented Aug 4, 2020

And what @elibarzilay mentions also happens when the workaround mentioned in #33575 (comment) is used.

@elibarzilay
Copy link
Contributor

@sandersn: I just tried #39770, and it doesn't fix this issue or the any that I mentioned above.

elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 7, 2020
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Aug 7, 2020
elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 7, 2020
elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 8, 2020
elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 10, 2020
elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 11, 2020
Nameless jsdoc typedefs have their exportedness controlled by the
exportedness of the location they pull their name from.

Fixes microsoft#33575.
elibarzilay added a commit to elibarzilay/TypeScript that referenced this issue Aug 11, 2020
Nameless jsdoc typedefs have their exportedness controlled by the
exportedness of the location they pull their name from.

Fixes microsoft#33575.
@elibarzilay
Copy link
Contributor

Quick note²: The /** @type {import("./my-enum.js").default} */ thing is working with the fix too.

elibarzilay added a commit that referenced this issue Aug 12, 2020
Nameless jsdoc typedefs have their exportedness controlled by the
exportedness of the location they pull their name from.

Fixes #33575.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: JSDoc Relates to JSDoc parsing and type generation Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
10 participants