Skip to content

TypeScript errors with modulesΒ #267

@joshkel

Description

@joshkel

According to Are the Types Wrong, memoize-one has an incorrect default export.

This can cause errors with TypeScript, depending on tsconfig.json settings. For example:

  • If using CommonJS (e.g., package.json "type": "commonjs") and tsconfig.json "module": "node16", "moduleResolution": "node16", then everything works.
  • If using ESM (e.g., package.json "type": "module") and tsconfig.json "module": "node16", "moduleResolution": "node16", problems arise:
    • If you try to import and use memoizeOne directly, the TypeScript compiler throws an error at compile time:
      import memoizeOne from 'memoize-one';
      // This expression is not callable.
      //  Type 'typeof import("node_modules/memoize-one/dist/memoize-one")' has no call signatures.ts(2349)
      const memoized = memoizeOne((a: number, b: number) => a + b);
    • However, if you work around that by adding .default, you get an error at runtime:
      import memoizeOne from 'memoize-one';
      // TypeError: memoizeOne.default is not a function
      const memoized = memoizeOne.default((a: number, b: number) => a + b);

As I understand it, there are two possible solutions:

  1. Hand-write a .d.ts file that reflects the CommonJS export assignment approach used by the Rollup-generated memoize-one build. (There may be a way to get tsc to do this for you, but I haven't been able to figure it out.) I believe that this could be done in a semver-patch release.
declare namespace memoizeOne {
    export type EqualityFn<TFunc extends (...args: any[]) => any> = (newArgs: Parameters<TFunc>, lastArgs: Parameters<TFunc>) => boolean;
    export type MemoizedFn<TFunc extends (this: any, ...args: any[]) => any> = {
        clear: () => void;
        (this: ThisParameterType<TFunc>, ...args: Parameters<TFunc>): ReturnType<TFunc>;
    };
}
declare function memoizeOne<TFunc extends (this: any, ...newArgs: any[]) => any>(
    resultFn: TFunc, isEqual?: memoizeOne.EqualityFn<TFunc>
): memoizeOne.MemoizedFn<TFunc>;
export = memoizeOne;
  1. Add full-fledged module support: update memoize-one's package.json to export its ESM build via exports (so Node.js, and TypeScript when using node16 module resolution, can see it), with ESM-specific types. This may be a semver-major change.

If you're interested in one of these approaches, I can try and open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions