tezvyn:

How does export = differ from export default in TypeScript declarations?

AI-drafted, machine-checkedintermediate

It tests CommonJS to ES module interop in TypeScript. export = maps to the entire module.exports object and must be imported with import = require() or ES interop, while export default creates a named binding. A red flag is claiming they are interchangeable.

WHAT THIS TESTS: Whether you understand that TypeScript's type system must model two different module systems faithfully. CommonJS uses module.exports = to reassign the entire exported object, while ES modules use a default export binding. TypeScript needs export = to represent the former because export default describes a different structural shape on the import side.

A GOOD ANSWER COVERS: First, the mechanical difference: export = corresponds to the whole module.exports assignment, so it exports exactly one entity that can be a function, object, or class. Second, the import-side contract: consumers must use import foo = require('foo') or enable esModuleInterop and allowSyntheticDefaultImports to bring it in as a default. Third, why export default is wrong for legacy CommonJS: it creates a named export called default that does not exist on the actual module.exports object unless the runtime or compiler synthesizes one. Fourth, the compiler flag implications: without esModuleInterop, writing export default in a declaration file for a classic module.exports = library will cause type errors on import.

COMMON WRONG ANSWERS: Claiming that export default and export = are interchangeable in declaration files. Stating that require() always returns the default export. Forgetting that export = prevents named exports alongside it in the same module, whereas export default can coexist with other named exports. Suggesting that modern ES module syntax alone is sufficient without mentioning the interop flags.

LIKELY FOLLOW-UPS: How would you write the declaration file if the library also attaches properties to the exported function? When should you use export as namespace Foo versus export =? How does Node16 module resolution change the way these declarations are consumed? What happens if the consumer uses a named import like import { foo } with an export = declaration?

ONE CONCRETE EXAMPLE: Suppose a CommonJS library does module.exports = function greet(name) { return 'Hello ' + name; }. The correct .d.ts file declares function greet(name: string): string; then export = greet;. A consumer using classic TypeScript must write import greet = require('my-lib');. If they instead write import greet from 'my-lib'; it only compiles when esModuleInterop is true because the compiler injects a synthetic default. Writing export default function greet... in the declaration file would be incorrect because it tells TypeScript there is a property literally named default on the exports, which the original CommonJS code does not create.

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.