Code Monkey home page Code Monkey logo

Comments (88)

alexreardon avatar alexreardon commented on June 26, 2024 13

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

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024 4

Well another option is named only exports.

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024 3

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.

hlolli avatar hlolli commented on June 26, 2024 3

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.

TrySound avatar TrySound commented on June 26, 2024 3

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

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024 2

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.

tyleo avatar tyleo commented on June 26, 2024 2

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.

theKashey avatar theKashey commented on June 26, 2024 2

So! Working for TypeScript #72!!!

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024 2

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.

MrKWatkins avatar MrKWatkins commented on June 26, 2024 1

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.

TrySound avatar TrySound commented on June 26, 2024 1

This is the best and not only for typescript
https://basarat.gitbooks.io/typescript/docs/tips/defaultIsBad.html

from memoize-one.

damiangreen avatar damiangreen commented on June 26, 2024 1

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.

sbaechler avatar sbaechler commented on June 26, 2024 1

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.

TrySound avatar TrySound commented on June 26, 2024 1

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

theKashey avatar theKashey commented on June 26, 2024 1

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)

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024 1

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

alexreardon avatar alexreardon commented on June 26, 2024

@TrySound thoughts?

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

@theKashey cjs bundle is matched to esm bundle by the way, it's typescript fault.

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

Actually there is esModuleInterop flag which fixes this behaviour in typescript similar to "magical" (it's not) babel way.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

It should be default since v3 but "TS has such big ecosystem".

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

To typescript? I'm not. Users should enable it and fix all modules in DefinitelyTyped.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

Or do you mean named export?

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

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

alexreardon avatar alexreardon commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

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

TrySound avatar TrySound commented on June 26, 2024

@theKashey It's not the best option. It's a hack for hacky ecosystem.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

Flow is not opinionated and that's why it's so beautiful.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

@theKashey Okay, how such export should look like? Like this { default: nowTryToInteropThis }?

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

Technically -

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports = memoizeOne;
exports.default = memoizeOne;

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

That could be a little problem.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

Babel moved from this hack two major versions ago.

from memoize-one.

billiegoose avatar billiegoose commented on June 26, 2024

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.

billiegoose avatar billiegoose commented on June 26, 2024

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.

hlolli avatar hlolli commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

esModuleInterop will fix the problem.

from memoize-one.

billiegoose avatar billiegoose commented on June 26, 2024

@hlolli you can use https://npmjs.org/package/@stoplight/memoize-one (based on #40)

from memoize-one.

damiangreen avatar damiangreen commented on June 26, 2024

Is there a resolution for this in SSR apps?

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

@damiangreen esModuleInterop: true

from memoize-one.

damiangreen avatar damiangreen commented on June 26, 2024

eek, turning that on gives me about 30 TS2349 errors across my application, not really a solution @TrySound without big refactorings

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

Try allowSyntheticDefaultImports

from memoize-one.

damiangreen avatar damiangreen commented on June 26, 2024

I have that enabled already :/

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

Well, 30 import statements is not so much to tweak.

from memoize-one.

sbaechler avatar sbaechler commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

@sbaechler Why is it different from import memoizeOne from 'memoize-one';?

from memoize-one.

sbaechler avatar sbaechler commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

@sbaechler Do you use babel to transpile TS or ts-jest?

from memoize-one.

skidding avatar skidding commented on June 26, 2024

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.

damiangreen avatar damiangreen commented on June 26, 2024

@skidding this works a treat, thanks for posting

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

@TrySound should we add the definition of @skidding to the project?

from memoize-one.

pablofmena avatar pablofmena commented on June 26, 2024

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 and b to the parameters, they are named newArgs and oldArgs to give a little bit more context.
  • Using a generic type argument as well on EqualityFn to take advantage of the built-in Parameters<T> type and avoid the use of the permissive any type. This way you also leverage type inference while passing this parameter, so no need to type the arguments yourself.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

And yeah, having builtin definitions will be good for ts users.

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

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

TrySound avatar TrySound commented on June 26, 2024

Yes, I think so with TS definition and output.exports: 'named'

from memoize-one.

thomasmikava avatar thomasmikava commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

@alexreardon Another solution is dropping default export.

import { memoizeOne } from 'memoize-one';

from memoize-one.

thomasmikava avatar thomasmikava commented on June 26, 2024

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

TrySound avatar TrySound commented on June 26, 2024

@thomasmikava
It's proposal for the project.
Do you have esModuleInterop or allowSyntheticDefaultImports enabled?

from memoize-one.

thomasmikava avatar thomasmikava commented on June 26, 2024

@TrySound
No, I don't

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

They should be enabled to provide cjs/esm interop.

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

Not working in Jest/node environment in the same way it was not working before.
Cjs bundle is broken without esModuleInterop

from memoize-one.

alexreardon avatar alexreardon commented on June 26, 2024

PR welcome @theKashey 👍

from memoize-one.

haraldschilly avatar haraldschilly commented on June 26, 2024

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.

alexreardon avatar alexreardon commented on June 26, 2024

@theKashey i think having the named export is the least strange. Thoughts @TrySound ?

export default function memoizeOne(){...}
export { memoizeOne };

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

That's the only way to fix the situation without a breaking change.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

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.

theKashey avatar theKashey commented on June 26, 2024

But that would be a breaking change. However, I definitely agree - that would be the best solution.

from memoize-one.

oonsamyi avatar oonsamyi commented on June 26, 2024

@alexreardon @theKashey @TrySound
Any activities?
Can we add named export and leave default export?
I can make pull-request.

from memoize-one.

TrySound avatar TrySound commented on June 26, 2024

@oonsamyi Why not enable interop on your side?

from memoize-one.

oonsamyi avatar oonsamyi commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

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.

theKashey avatar theKashey commented on June 26, 2024

Why not enable interop on your side?

then classnames would be broken :)

from memoize-one.

oonsamyi avatar oonsamyi commented on June 26, 2024

@alexreardon Can I make a pull request?

from memoize-one.

mits87 avatar mits87 commented on June 26, 2024

Any news?

from memoize-one.

filipef101 avatar filipef101 commented on June 26, 2024

Let's go

from memoize-one.

theKashey avatar theKashey commented on June 26, 2024

Wasn't it solved in a new version?

from memoize-one.

mits87 avatar mits87 commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

@mits87 Try to enable esModuleInterop in TS config

from memoize-one.

mits87 avatar mits87 commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

Let's kill default import.
#86

from memoize-one.

tamazlykar avatar tamazlykar commented on June 26, 2024

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.

TrySound avatar TrySound commented on June 26, 2024

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

alexreardon avatar alexreardon commented on June 26, 2024

Just to make peoples lives easier ^

from memoize-one.

cwood-panopto avatar cwood-panopto commented on June 26, 2024

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.