memoize-one: Not working for typescript

Actually the problem is not with typescript - the problem is with rollup.

https://unpkg.com/memoize-one@4.0.2/dist/memoize-one.cjs.js contains

module.exports = index;

which should be imported as import * as memoizeOne

while https://unpkg.com/memoize-one@4.0.2/dist/memoize-one.esm.js contains

export default index;

which should be imported as import memoizeOne

Result - the code for nodejs (~jest) require one behaviour, while the code for webpack(uses esm bundle) requires another.

It is not a problem for js/flow, as long babel is doing some around magic default imports, but typescript is quite strict about it.

The cjs bundle should match esm bundle.

(and fixing this would introduce a breaking change)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 10
  • Comments: 88 (58 by maintainers)

Commits related to this issue

Most upvoted comments

I’m happy to add a named export if it is easier for people

Well another option is named only exports.

Or just enable esModuleInterop and ask ts maintainers to do the same 😃

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 😃

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.

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';

So! Working for TypeScript #72!!!

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.

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. https://github.com/jaredpalmer/formik/pull/973#issuecomment-428012717

👍 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)

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, so cjs export would be both cjs and esm compatible. Hacky hack, but would work. (don’t tell anybody I’ve proposed it)

@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.

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.

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.

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");
    }
}