vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.69k stars 26.62k forks source link

[NEXT-776] commonjs types for `next/jest` are incorrect #37524

Open ryami333 opened 2 years ago

ryami333 commented 2 years ago

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 21.4.0: Fri Mar 18 00:46:32 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T6000
Binaries:
  Node: 16.15.1
  npm: 8.11.0
  Yarn: 1.22.18
  pnpm: N/A
Relevant packages:
  next: 12.1.7-canary.31
  react: 17.0.2
  react-dom: 17.0.2

What browser are you using? (if relevant)

Not applicable

How are you deploying your application? (if relevant)

Not applicable

Describe the Bug

Using the boilerplate from the documentation for Setting up Jest (with the Rust Compiler) and with tsconfig.json#compilerOptions.checkJs enabled a type-error is generated.

error TS2349: This expression is not callable.
  Type 'typeof import("/{projectPath}/node_modules/next/jest")' has no call signatures.

4 const createJestConfig = nextJest({
                           ~~~~~~~~

The issue appears to be with the commonjs/esm interoperability layer, because:

Known Workarounds

If you bypass the next/jest entrypoint and its interoperability layer, and instead require from the dist/build folder then it works as expected. Ie.

- const nextJest = require("next/jest");
+ const nextJest = require("next/dist/build/jest/jest").default;

Expected Behavior

There should be no type-errors when using next/jest as documented and with checkJs enabled.

To Reproduce

  1. Install typescript and next.
  2. Create a javascript file (nominally called jest.config.js) and populate it with the contents of the code-snippet in Setting up Jest (with the Rust Compiler).
  3. Add a tsconfig.json and ensure that compilerOption.allowJs and compilerOption.checkJs are both set to true, so that the jest.config.js file is typechecked.

See here for a minimal reproducible example.

NEXT-776

SukkaW commented 2 years ago

Duplicated https://github.com/vercel/next.js/issues/36534.

The issue has been fixed in https://github.com/vercel/next.js/pull/36824.

ryami333 commented 2 years ago

@SukkaW I don't think this is a duplicate - as I indicated in the PR this is still an issue in Next canary (which presumably includes the "fix" in https://github.com/vercel/next.js/pull/36824.)

I just updated my minimal reproducible example to use 12.1.7-canary and it is indeed still a problem.

SukkaW commented 2 years ago

I just updated my minimal reproducible example to use 12.1.7-canary and it is indeed still a problem.

I see why this is an issue.

In Next.js, we add a build flag interopClientDefaultExport to enable a hack for default export. It allows you to import the module in both ways:

const { default: nextJest } = require('next/jest');
const nextJest = require('next/jest');

However, you can only do this if you want to have type definition:

import nextJest from 'next/jest';
const { default: nextJest } = require('next/jest');
import { default: nextJest } = require('next/jest');

Let me see if we can overcome this.

muhammadAhmed3 commented 2 years ago

Also facing the same issue.

ryami333 commented 2 years ago

Just updated the codesandbox repro to use 12.2.6-canary and confirmed that it's still not working.

SukkaW commented 2 years ago

@ryami333 Just use default export as a workaround.

The issue can not be fixed by Next.js. It is TypeScript's fault that it does not support exporting both module.exports and module.exports.default. You should blame TypeScript for that.

What Next.js can do is to have both named export and default export, which I have brought up in #38503 and is rejected by the Next.js team.

frei-x commented 1 year ago

mine too