-
-
Notifications
You must be signed in to change notification settings - Fork 53
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
mem intellisense broken for JS #31
Comments
I'm preparing for the future. I'm not interested in rewriting all my type definitions when I move my packages to ES2015 module syntax, so my type definitions assume it's module and I also export a I don't see the problem with having to use |
With the current designs under consideration |
In |
I'm unsure how this is different than this issue about how the same problem used to exist in |
When I switch my Node.js modules to ESM, I won't have to inconvenience TypeScript users to update their imports. If I use |
The future where I don't use |
I didn't add the Flow declaration. |
I think we were the first to notice the problem because the people most affected by the problem are JS users of VS Code, who don't even know they're using We detected it because @BendingBender is a major contributor to Definitely Typed and we took notice when he started removing packages instead of adding them. :) |
I think what @weswigham tries to say here is that the current state of affairs according importing CJS modules from ESM modules is that the whole const myModule = {prop: 'foo'};
module.exports = myModule;
module.exports.default = myModule; then in an ESM module, this would look like this: import myModule from 'my-module';
console.log(myModule.prop);
// => 'foo'
console.log(myModule.default.prop);
// => 'foo' There is, however, a note that named imports should be supported when importing CJS modules from ESM modules. |
@sandersn Intellisense interop was not on my radar. I started upstreaming the definitions because it became a burden to keep them up-to-date regarding the pace in which @sindresorhus' modules keep changing. |
Having the default in addition to the namespace assignment should be sufficient here. Generally people will need to be swapping from But even that has problems, and not with TS. If
You're going to inconvenience your TS users less than everyone else, since all your cjs users, under current proposals, will just be completely broken without a reasonable way to use your module. At least your TS users will have the option of running a quick fix (or already be correct) on their import and upgrading their codebase - your cjs users are just dead under the current esm/cjs interop scheme (because replacing require with a promise-returning dynamic import isn't really a practical thing for most places). :( |
As you said, current designs specify that using (async () => {
await import('esm');
})(); will be possible from CJS modules. Which will import such modules exposing them the way they are authored for ESM, mostly meaning that there will be a |
You can't seriously update any large program using the pattern. For one, is forces you to defer all of your own module's exports because your module now has an async dependency, and you somehow need to report that (eg, by exporting a promise to the real exports namespace), and so the async taint transitively spreads to every dependency. If I were using, eg, |
What I'm getting at here, in the abstract, is that there's no clean migration path in node's esm plan right now. Don't try to craft your declarations for that future, because it doesn't work as well as you think it does, is still in flux, and will only hurt your consumers today. |
Is there any kind of discussion on this topic? I did a quick search but I seem to miss it.
Why wouldn't mem be directly callable provided @sindresorhus moves his modules to ESM, which he plans to do? |
@sindresorhus I think this is a very valid point to consider. What do you think? |
As I said, if both consumer and producer are esm, it'd work fine, but if Lemme be blunt with y'all: DO NOT WRITE DECLARATION FILES TODAY FOR TOMORROW'S NODE ESM IMPLEMENTATION.
|
I just wish someone had told us all this a month ago before we made 100+ declaration files... So let me just get this straight:
Anything else? (Please look closely at the declaration file, I don't want another round of rewrites) |
Correct.
We have to use the following construct: declare namespace foo {
function namedExportFn(): void;
// importable via: import {namedExportFn} from 'foo';
interface Foo {}
// importable via: import {Foo} from 'foo';
}
declare function foo(fooArg: foo.Foo): void;
// importable via: import foo = require('foo');
// or with allowSyntheticDefaultImports/esModuleInterop: import foo from 'foo';
export = foo;
Yes, if they don't set either |
How would it look like to import |
There are 2 options: // 1st
import foo = require('foo');
const fooVal: foo.Foo = ...;
foo.namedExportFn();
// 2nd
import foo = require('foo');
import {namedExportFn, Foo} from 'foo'; If your default export is a class the whole definition becomes much more awkward: declare namespace Foo {
// Only interfaces may be declared here. If you have a value,
// you'll need to declare it as a static member on the class
// or via an intersection type.
}
declare class Foo {}
export = Foo; |
All in all, this is considered more of a hack than a solution because combining import * as foo from 'foo';
foo(); // shouldn't be primitive or callable as per ES spec Only in case of very simple modules that don't have interfaces to export and thus where you can omit the namespace declaration will the compiler enforce the |
Or if you set |
@BendingBender Alright. Let's use the correct CommonJS-compatible syntax going forward. I will try to update existing definitions when I have time, but I could use some help with that too. |
@sindresorhus I will happily help you with this, most of that stuff comes from me after all. Just for me to know how you plan to change existing declarations: do you want to keep the |
Is there a way to move to CommonJS-syntax while still not doing a breaking change? I was under the assumption we had to completely move over and do a major bump. |
We could still leave the This would be possible: declare namespace foo {
interface Foo {}
}
declare const foo: {
(fooArg: foo.Foo): void;
namedExportFn(): void;
default: typeof foo;
}
export = foo; |
Alright, let's do that for the packages where we already released the type definitions, with a TODO comment about removing it in the next major release. |
This issue matches PR #30. I think it's better to have a discussion here.
I believe this issue applies to all your packages that recently added types via d.ts files. I assume that the purpose was to improve intellisense. Right now, it works fine for Typescript users who have
--esModuleInterop
turned on, but for normal JS use it's broken:isn't callable, even though the primary export of this package is a function.
Instead, people have to change their code to
which seems like it goes against the normal commonjs usage.
The d.ts file seems like it exists solely to provide better intellisense, and it consists solely of typescript syntax, so I think using the typescript syntax for commonjs exports make sense. That way people who use mem in editors with intellisense will not have to add
.default
to all their existingrequire('./mem')
calls.The text was updated successfully, but these errors were encountered: