TypeScript

Fix Day.js: dayjs_1.default is not a function

Separate a successful type check from a callable runtime import, and avoid the namespace workaround that fails when interop is enabled.

Mahdi Ben RhoumaMahdi Ben Rhouma
8 min read

TL;DR#

For a TypeScript build emitting CommonJS, keep the Day.js default import and enable esModuleInterop in the configuration that actually emits the failing file. Check the resulting JavaScript: the fixed build wraps the require call rather than reading an undefined default property directly. allowSyntheticDefaultImports alone does not perform that runtime conversion.

Do not simultaneously switch to a callable namespace import. That workaround changes behaviour when interop is enabled, and it is not a universal fix for this error.

The original report imported Day.js into a Pino timestamp callback and started the application with ts-node-dev in transpile-only mode. Its first date call failed with:

text
TypeError: (0 , dayjs_1.default) is not a function

The report does not provide its complete TypeScript configuration. The controlled reproduction below therefore proves a matching failure path, rather than claiming to reconstruct every setting of that application. No logger installation is required to reproduce the date-call failure.

Why it happens#

There are separate values to distinguish: the raw CommonJS export, the generated JavaScript binding, and a native ESM namespace.

The installed Day.js package used in the reproduction exposes a callable CommonJS value. Requiring it returned a function, while its default property was undefined. Its metadata pointed to dayjs.min.js, and the official declarations use export-equals syntax for the callable Day.js value.

That does not mean default imports are always forbidden. The Day.js TypeScript instructions explicitly document the default-import workflow when interop is enabled. The compiler must connect that import syntax to the package's actual export shape.

Without the wrapper, the reproduced CommonJS output loaded the function into dayjs_1 and then attempted to call dayjs_1.default. It was calling an undefined property of the loaded function, not failing to find or install Day.js.

Fix#

1. Confirm which compiler configuration emits the file#

Inspect the effective configuration for the project that runs the failing import:

bash
npx tsc --showConfig --project tsconfig.json

Check the module output and the two interop-related options. If the application runner selects another configuration, inspect that configuration as well. A settings change in an unrelated root file will not change the JavaScript already running in the child project.

If the compiler command itself cannot start, follow the local TypeScript compiler setup. That command-launch problem occurs before import checking or JavaScript emission; it is not this runtime TypeError.

2. Retain the default import and change the emit setting#

Merge this option into the existing compilerOptions object; preserve the application's other settings:

json
{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

The TypeScript esModuleInterop reference explains how the option changes checking and emits compatibility helpers for CommonJS imports. It also enables synthetic-default checking unless that option is explicitly overridden. In the reproduction, synthetic-default checking was already enabled, so the only changed setting was esModuleInterop.

The application import remains:

typescript
import dayjs from 'dayjs';
 
console.log(dayjs('2026-10-13').format('YYYY-MM-DD'));

For an existing CommonJS build, this repairs the import bridge. It does not require moving the whole application to native ESM, updating Day.js, replacing the logger or installing a separate declaration package. Day.js ships its own TypeScript declarations.

3. Rebuild and exercise the actual call#

Compile the project rather than passing an individual source file to a separate ad hoc build command:

bash
npx tsc --project tsconfig.json

Run the rebuilt entry point selected by the application's normal start command. For the small fixture, that was the emitted index.js file in its configured output directory. A successful type check is only one verification step: the date factory must actually execute too.

If your project delegates emission to another tool, inspect that tool's output. A tsc check with correct options does not prove that a different transpiler emitted the same wrapper. If interop is already enabled, do not keep toggling it; determine which generated file, configuration and runner produced the observed call instead.

Verify the fix#

The error and repair were reproduced in an isolated Docker container on 13 October 2026, with Node 22.23.3, Day.js 1.11.23 and TypeScript 5.9.3. Those are the tested versions, not a claim that a fix shipped in a particular release.

The baseline compiled the default import with CommonJS output, esModuleInterop disabled and allowSyntheticDefaultImports enabled. The compiler exited successfully, but executing the emitted file produced the exact TypeError above. Its relevant output was:

javascript
const dayjs_1 = require("dayjs");
console.log((0, dayjs_1.default)('2026-10-13').format('YYYY-MM-DD'));

Only esModuleInterop was changed. The same source, package version and runtime then compiled and ran successfully. The relevant emitted import became:

javascript
const dayjs_1 = __importDefault(require("dayjs"));

This line is an inspection excerpt, not a standalone script: the compiler also emitted the helper definition. The fixture printed:

text
2026-10-13

The synthetic-default-imports reference separates type checking from emission. The negative control disabled only synthetic-default checking while leaving interop off. TypeScript then reported TS1259, but executing its emitted file still produced the same runtime failure. Removing the checking permission exposed a diagnostic; it did not manufacture the missing runtime binding.

The site's TypeScript export-mismatch guide covers compiler diagnostics such as TS1259 and TS2305 more broadly. This Day.js incident is the distinct case where the check can be green and the eventual function call still fails.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

Why the namespace answer depends on the mode#

One source answer recommends importing every export as a namespace. That was tested separately:

typescript
import * as dayjs from 'dayjs';
 
console.log(dayjs('2026-10-13').format('YYYY-MM-DD'));

With the reproduced CommonJS configuration and interop disabled, this compiled and ran. With interop enabled, the compiler rejected the call with TS2349: the namespace had no call signatures. The test deliberately executed the emitted file from that rejected compilation and confirmed TypeError: dayjs is not a function.

The difference is material. A namespace object is not the same value as the callable export it contains. Do not combine the namespace workaround and the interop fix just because both appear in answers to the same question.

For a CommonJS project that deliberately retains interop disabled, another tested import spelling matches Day.js's export-equals declaration:

typescript
import dayjs = require('dayjs');
 
console.log(dayjs('2026-10-13').format('YYYY-MM-DD'));

That compiled and ran in the fixture without changing the package. It is a CommonJS alternative, not an instruction to replace imports throughout an existing native ESM application.

Native ESM does not use the same bridge#

The accepted answer's broad statement that Day.js has no default entry should not be applied to every loader. The Node ESM interoperability documentation describes how Node supplies a default binding for a CommonJS module.

A native .mjs control imported Day.js without TypeScript emission. Its default binding was callable, its namespace was an object, and that namespace's default property was callable. The same date factory succeeded. This is why an import can work in an ESM entry point while an unwrapped CommonJS build fails on a missing default property.

Keep loader failures separate from callability failures. An existing native ESM application can fail earlier on a relative import missing its extension; the Node relative-import extension fix covers that case. If a different dependency instead throws ERR_REQUIRE_ESM through a ts-node CommonJS hook, use the ts-node ESM loading explanation. Neither error is repaired by blindly changing the Day.js namespace.

The useful verification is specific: identify the loaded export, inspect the emitted import, and run the date call under the same runtime as the failing application. Keep the default import paired with a working CommonJS interop bridge, or choose the tested CommonJS import-equals alternative deliberately.

Further reading: Fix "X is not a constructor" from a plain require().

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote