8000 TypeScript types fail with ESM (type: module) + TSConfig module: node16 · Issue #46676 · vercel/next.js · GitHub
[go: up one dir, main page]

Skip to content
TypeScript types fail with ESM (type: module) + TSConfig module: node16  #46676
@karlhorky
Description
@karlhorky

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #22 SMP Tue Jan 10 18:39:00 UTC 2023
    Binaries:
      Node: 16.17.0
      npm: 8.15.0
      Yarn: 1.22.19
      pnpm: 7.1.0
    Relevant packages:
      next: 13.2.4-canary.0
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

TypeScript support

Link to the code that reproduces this issue

https://codesandbox.io/p/sandbox/floral-thunder-44jpww?file=%2Fpages%2Findex.tsx

To Reproduce

  1. Open reproduction above
  2. Observe TypeScript error on dynamic() function
    This expression is not callable.
    Type 'typeof import("/project/sandbox/node_modules/next/dynamic")' has no call signatures.
    
  3. Observe TypeScript error on Image component
    JSX element type 'Image' does not have any construct or call signatures.typescript(2604)
    

Screenshot 2023-03-02 at 12 18 18

Screenshot 2023-03-02 at 12 16 58

This occurs with all import paths with slashes into next eg:

  • next/dynamic
  • next/image
  • next/link
  • next/navigation
  • next/script

Describe the Bug

The TypeScript types for the imports at the paths mentioned above fail when using:

  1. ESM ("type": "module" in package.json)
  2. TSConfig "module": "node16", which was seemingly implemented by @loettz in Add support for tsconfig 'nodenext' | 'node16' #44177

The code however still runs, so it seems to be a problem with the Next.js types and ESM <> CommonJS interop.

I'm guessing that since Next.js is CommonJS, the types of these exports on all *.d.ts files are actually wrong:

import Link from './dist/client/link'
export * from './dist/client/link'
export default Link

I guess the correct type would actually use the unusual TypeScript syntax export =, like my PR over here:

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/64137/files

cc @andrewbranch @fluggo @cseas @lfades

Workaround

A workaround is to type the import as the .default property, as @kachkaev shows in this discussion comment:

-import x from "x";
+import _x from "x";
+const x = _x as unknown as typeof _x.default;

Expected Behavior

The import should work out of the box and no TypeScript errors should appear.

See also

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    TypeScriptRelated to types with Next.js.bugIssue was opened via the bug report template.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0