Comments (88)
I'm happy to add a named export if it is easier for people
from memoize-one.
Well another option is named only exports.
from memoize-one.
The best option I could provide, would be a :badjookeeee: option - rewrite memoize-one to TS, and provide .flow types in a separate, ie "revert" how it works today.
TS could generate "default" exports, understandable both by TS and JS.
from memoize-one.
Thanks for the replies. I tried the esModuleInterop
(it works!) and it seemed to me, that I had to use it sooner or later, since import * as ...
is quite ugly. I'll make a bet still that this will not be the last of tickets relating this issue if this is needed :)
from memoize-one.
Or just enable esModuleInterop and ask ts maintainers to do the same :)
from memoize-one.
This is the old issue with typescript itself and default exports. My solution is getting rid from default exports in the next major release. They are quite useless.
I'm not alone.
jaredpalmer/formik#973 (comment)
from memoize-one.
This was broken for me. I eventually fixed it but I consider that work to be more of a chain of unfortunate hacks than I consider it a fix.
I'm in a monorepo using memoize-one across a few projects. We have an electron project and a website. memoize-one did not work out of the box on the electron project. Out of roughly 15 other modules I am using, memoize-one is the only module which does not work out of the box. To fix the electron project, I isolated memoize-one in its own project in our monorepo with the following code:
import * as memoizeOne_ from "memoize-one";
export = <T extends (...args: any[]) => any>(resultFn: T, isEqual?: memoizeOne_.EqualityFn): T => {
return (memoizeOne_ as any)(resultFn, isEqual);
};
This was working fine for awhile but broke when we started to use memoize-one on our website. Luckily, since I isolated memoize-one to its own project I could add "esModuleInterop": true
to it without impacting the other projects. After this I updated my code:
import * as memoizeOne_ from "memoize-one";
export = <T extends (...args: any[]) => any>(resultFn: T, isEqual?: memoizeOne_.EqualityFn): T => {
return (memoizeOne_ as any).default(resultFn, isEqual);
};
I'm not personally thrilled about this solution but I'm glad that I could at least isolate the impact of esModuleInterop
to a single project.
I think memoize-one is a great tool and it could be even greater if it worked out of the box for typescript projects in a standard way without requiring esModuleInterop
.
from memoize-one.
So! Working for TypeScript #72!!!
from memoize-one.
i'm totally open to adding a minor
release which allows people to use memoize-one
as a named import
export const memoizeOne = memoizeOne;
export const memoize = memoizeOne;
import { memoizeOne } from 'memoize-one';
// OR
import { memoize } from 'memoize-one';
from memoize-one.
I've added the following function as a workaround which I call at the start of my tests:
export function ensureMemoizeOneInitialized()
{
if (typeof memoize === "undefined")
{
/* tslint:disable:no-var-requires */
(memoize as any) = require("memoize-one");
}
}
from memoize-one.
This is the best and not only for typescript
https://basarat.gitbooks.io/typescript/docs/tips/defaultIsBad.html
from memoize-one.
actually i started trying to refactor my app, but it turns out it would require touching more than 30 imports but its about a years worth of dev and i dont really want to to a full regression test just to import a library , not on a friday night anyway.
from memoize-one.
We are using Babel. The config is based on a fork of create-react-app 1. I noticed that this issue does not occur anymore on create-react-app 2 based projects.
from memoize-one.
@alexreardon I guess the issue will never end until we migrate to require('memoize-one').default
solution. This can be done with output.exports: 'named'
option.
from memoize-one.
There are two ways, please pick any to "fix" the issue, without breaking changes for cjs
and non typescript
users (ie node):
- keep the current "default" export, and add memoizeOne as a named export next to it. However - that would bring some confusion.
- keep everything as is. Define
.default
on memoizeOne itself, socjs
export would be bothcjs
andesm
compatible. Hacky hack, but would work. (don't tell anybody I've proposed it)
from memoize-one.
👍 import { memoizeOne } from 'memoize-one';
- it will be better autoimportable.
Plus every time you import memoizeOne from 'memoize-one'
eslint will complain about the named export and propose a change (actually that could break builds, but 😅 it is a good to have feature)
from memoize-one.
@TrySound thoughts?
from memoize-one.
As you mentioned @theKashey we are using rollup to generate the bundles. It sounds like there is an issue with the cjs
bundle. Is there an option we can change for the rollup build...?
from memoize-one.
@theKashey cjs bundle is matched to esm bundle by the way, it's typescript fault.
from memoize-one.
I would be keen to find a way forward in our generated code. Ideally it would work with TS out of the box. Any thoughts @TrySound?
from memoize-one.
Actually there is esModuleInterop
flag which fixes this behaviour in typescript similar to "magical" (it's not) babel way.
from memoize-one.
It should be default since v3 but "TS has such big ecosystem".
from memoize-one.
from memoize-one.
To typescript? I'm not. Users should enable it and fix all modules in DefinitelyTyped.
from memoize-one.
Or do you mean named export?
from memoize-one.
Please don't use esModuleInterop
or allowSyntheticDefaultImports
, it will require target consumer to set it, and this is something you shall not ask for.
PS: And also affects imports, not exports.
from memoize-one.
@theKashey That's the point. It should be default. Ecosystem is broken now. It's just doesn't work for many packages.
from memoize-one.
To typescript? I'm not. Users should enable it and fix all modules in DefinitelyTyped.
@TrySound I misunderstood you. I thought we could add a simple rollup plugin and be done with this issue
It sounds like you have some insight into this @theKashey, any thoughts on how to proceed?
from memoize-one.
@theKashey What is the point of esModuleInterop if it doesn't work with any typings at all? What for they provided broken configuration?
from memoize-one.
@theKashey It's not the best option. It's a hack for hacky ecosystem.
from memoize-one.
Flow is not opinionated and that's why it's so beautiful.
from memoize-one.
@theKashey Okay, how such export should look like? Like this { default: nowTryToInteropThis }
?
from memoize-one.
Technically -
Object.defineProperty(exports, "__esModule", {
value: true
});
exports = memoizeOne;
exports.default = memoizeOne;
from memoize-one.
from memoize-one.
That could be a little problem.
from memoize-one.
Babel moved from this hack two major versions ago.
from memoize-one.
I'm running into this problem as well. Not sure if it's TypeScript per-se or Jest.
But the crux of it is that the CJS module needs to include a named export called "default". Pretty much like @theKashey showed.
I think that would fix it.
from memoize-one.
Just tried. Can't be done. (Seriously rollup
?) Default exports were such a fuckup. :(
I think the only way out is to release a new major version that breaks the way CJS currently works and forces it to use require('memoize').default
. I'll make a PR.
from memoize-one.
This is a problem for me on Typescript, it works
import * as memoizeOne from "memoize-one";
and
import memoizeOne from "memoize-one";
but with server side rendering, one will work on nodejs and one on in the browser, bot not both at the same time.
So if I'd want to do
import * as memoizeOne from 'memoize-one/dist/memoize-one.cjs';
which works both server and browser side, then tslint
will complain.
This is the only library of like 50 that behaves this differently between imports.
from memoize-one.
esModuleInterop will fix the problem.
from memoize-one.
@hlolli you can use https://npmjs.org/package/@stoplight/memoize-one (based on #40)
from memoize-one.
Is there a resolution for this in SSR apps?
from memoize-one.
@damiangreen esModuleInterop: true
from memoize-one.
eek, turning that on gives me about 30 TS2349 errors across my application, not really a solution @TrySound without big refactorings
from memoize-one.
Try allowSyntheticDefaultImports
from memoize-one.
I have that enabled already :/
from memoize-one.
Well, 30 import statements is not so much to tweak.
from memoize-one.
Another workaround is to create a new .js file with a named export:
export { default as memoizeOne } from 'memoize-one';
and import from there.
from memoize-one.
@sbaechler Why is it different from import memoizeOne from 'memoize-one';
?
from memoize-one.
I have no idea. It is not any different, but it is working. I guess Typescript or Jest are using a different import resolution since it is importing a .js file and not a .ts file.
The JS file has to be created in the user's project, not in memoize-one.
from memoize-one.
@sbaechler Do you use babel to transpile TS or ts-jest?
from memoize-one.
Not sure if we're all experiencing the same issue, but here's how I solved mine.
Added this declaration for memoize-one
in my project and removed @types/memoize-one
declare module 'memoize-one' {
export type EqualityFn = (a: any, b: any, index: number) => boolean;
declare function memoizeOne<T extends (...args: any[]) => any>(
resultFn: T,
isEqual?: EqualityFn
): T;
export = memoizeOne;
}
The problem could be that the official types are for 4.1 and I'm using 5.0.
If anyone wants to publish this to DefinitelyTyped (or in the memoize-one codebase directly) be my guest.
from memoize-one.
@skidding this works a treat, thanks for posting
from memoize-one.
@TrySound should we add the definition of @skidding to the project?
from memoize-one.
Hi, first thanks for this neat utility and for caring about the TypeScripters 😃
If you plan to make the type definition file part of the project, here my two cents for version 5:
declare function memoizeOne<T extends (...args: any[]) => any>(
resultFn: T,
isEqual?: memoizeOne.EqualityFn<T>
): T;
declare namespace memoizeOne {
type EqualityFn<T extends (...args: any[]) => any> = (
newArgs: Parameters<T>,
oldArgs: Parameters<T>
) => boolean;
}
export = memoizeOne;
- So instead of naming just
a
andb
to the parameters, they are namednewArgs
andoldArgs
to give a little bit more context. - Using a generic type argument as well on
EqualityFn
to take advantage of the built-inParameters<T>
type and avoid the use of the permissiveany
type. This way you also leverage type inference while passing this parameter, so no need to type the arguments yourself.
from memoize-one.
And yeah, having builtin definitions will be good for ts users.
from memoize-one.
@TrySound if we add a TS definition would this allow TS users to have correct typing without needing to do anything else?
from memoize-one.
Yes, I think so with TS definition and output.exports: 'named'
from memoize-one.
If I change
export = memoizeOne;
to
export default memoizeOne;
everything works fine. However, If I change import from
import memoizeOne from "memoize-one";
to
import * as memoizeOne from "memoize-one";
the compilation of my React project fails.
Thus, I am forced to change index.d.ts file as I said (or downgrade memoize-one)
from memoize-one.
@alexreardon Another solution is dropping default export.
import { memoizeOne } from 'memoize-one';
from memoize-one.
@TrySound In case of writing { memoizeOne }, I get the following message:
Module '"../../../../node_modules/@types/memoize-one"' has no exported member 'memoizeOne'
from memoize-one.
@thomasmikava
It's proposal for the project.
Do you have esModuleInterop
or allowSyntheticDefaultImports
enabled?
from memoize-one.
@TrySound
No, I don't
from memoize-one.
They should be enabled to provide cjs/esm interop.
from memoize-one.
Not working in Jest/node environment in the same way it was not working before.
Cjs bundle is broken without esModuleInterop
from memoize-one.
PR welcome @theKashey 👍
from memoize-one.
I also stumbled over this typerscript code vs. jest testing problem. What I ended up doing is this:
import * as memoizeOneModule from "memoize-one";
const memoizeOne =
typeof memoizeOneModule.default === "function"
? memoizeOneModule.default
: memoizeOneModule;
I hope the typescript gods have mercy …
from memoize-one.
@theKashey i think having the named export is the least strange. Thoughts @TrySound ?
export default function memoizeOne(){...}
export { memoizeOne };
from memoize-one.
That's the only way to fix the situation without a breaking change.
from memoize-one.
Having only named export is ok
export function memoizeOne(){...}
and less confusing for commonjs users
import { memoizeOne } from 'memoize-one';
const { memoizeOne } = require('memoize-one');
vs
import memoizeOne from 'memoize-one';
const memoizeOne = require('memoize-one').default;
from memoize-one.
But that would be a breaking change. However, I definitely agree - that would be the best solution.
from memoize-one.
@alexreardon @theKashey @TrySound
Any activities?
Can we add named export and leave default export?
I can make pull-request.
from memoize-one.
@oonsamyi Why not enable interop on your side?
from memoize-one.
When I add esModuleInterop
option to ts config several dozen typescript errors appear and part of unit tests fails. Typescript errors are not a problem for me. But the failure tests are a problem. I don't quite understand why tests fail with esModuleInterop option.
Now I turned off esModuleInterop
option and added next hack to jest config:
// project/fixDefaultImports.ts
jest.mock('memoize-one', () => ({
default: jest.requireActual('memoize-one'),
}));
// project/jest.config.js
module.exports = {
setupFilesAfterEnv: ['<rootDir>/enzyme.config.js', '<rootDir>/fixDefaultImports.ts'],
...
}
But it is hack...
Summary, I would like to work with default typescript config.
Is this issue accurate only with typescript? What about jest + pure javascript?
Is it hard to add named export? I think it is easy, memoize-one will be worked out of the box with typescript default config and many people will be grateful :)
P.S. React resolves this problem next way:
https://github.com/facebook/react/blob/master/packages/react/index.js#L16
It is cool because no matter what is used in the environment of the project: CommonJS or ES6 modules, javascript or typescript, webpack or rollup. It works for all the ones.
from memoize-one.
Summary, I would like to work with default typescript config.
This is not an option with typescript. You loose safety without strictNullChecks.
Is it hard to add named export?
This is inconsistent design. There should be either default or named export.
React resolves this problem next way:
React does not distribute esm and does not export function as default/module.exports.
But it is hack...
This is too, but this is how ts behaves by default.
import * as memoizeOne from 'memoize-one';
I'd say babel as compiler will solve all your issues.
from memoize-one.
Why not enable interop on your side?
then classnames would be broken :)
from memoize-one.
@alexreardon Can I make a pull request?
from memoize-one.
Any news?
from memoize-one.
Let's go
from memoize-one.
Wasn't it solved in a new version?
from memoize-one.
It looks like still there is a problem.
I have installed: "memoize-one": "^5.1.1"
When I'm trying to use it like that:
import memoizeOne from 'memoize-one';
I've got an error:
{
"errorType":"TypeError",
"errorMessage":"memoize_one_1.default is not a function",
"stack":[
"TypeError: memoize_one_1.default is not a function", "......"]
}```
from memoize-one.
@mits87 Try to enable esModuleInterop in TS config
from memoize-one.
Actually I can't use the esModuleInterop
option because I have a lot of libraries like:
import * as SQS from 'aws-sdk/clients/sqs';
and after enabled esModuleInterop
flag I've got errors like:
Misnamed import. Import should be named 'sqs' but found 'SQS'
or
Type originates at this import. A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Consider using a default import or import require here instead.
from memoize-one.
Let's kill default import.
#86
from memoize-one.
Any news?
I have a strange problem. I was using memoize-one without esModuleInterop and it works great with import like this:
import * as memoizeOne from 'memoize-one'
but when i set esModuleInterop to true and change import to import memoizeOne from 'memoize-one'
app still works but jest start to fails with TypeError: memoize_one_1.default is not a function
.
If I set a breakpoint around the place where memoize-one is used I see that memoize_one_1 looks like this:
memoize_one_1 : {
default: {
{
default: actual_function
}
}
}
App compiles with webpack and ts-loader, jest with ts-jest, typescript version is 3.7.5.
If this problem not relates to this library, sorry.
Any ideas why this happens will be appreciated.
from memoize-one.
@tamazlykar I faced this problem with webpack when some commonjs module imported esm version of library. Make sure you do not transpile modules by babel-loader.
from memoize-one.
Just to make peoples lives easier ^
from memoize-one.
@alexreardon With the revert in v5.2.1 is this an issue again? I am still having the error in jest with ts: TypeError: memoize_one_1.default is not a function
from memoize-one.
Related Issues (20)
- Memoize not working properly with `NaN` HOT 4
- Memoize not working properly with arrays HOT 2
- Memoize not working properly with objects and custom comparator HOT 1
- React useMemo style API HOT 2
- Doc: please update the performance numbers + the benchmark HOT 3
- Cannot find v5.2.0 via NPM HOT 1
- `5.2.0` introduces a breaking change HOT 28
- MD5 checksum for object parameters HOT 2
- PSA: Intention to remove ie11 support
- Don't allow `resultFn` to resolve to implicit any params HOT 4
- "This expression is not callable" type error when trying to use this package from ESM module HOT 2
- Analysis: 64% of dependency updates in this repository can be merged. HOT 1
- TypeScript typings of `EqualityFn` HOT 6
- Memoizing TypeScript functions with generics
- Does memoize-one support Promises? HOT 3
- TypeError: memoizeOne is not a function HOT 4
- Same parameters, different locations will also rerun HOT 2
- Simple code in TS not working HOT 3
- Memoize one is failing within a test environment. Value is not changed yet memoized function is called. HOT 2
- Misleading documentation HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from memoize-one.