[Typescript] The Verbatim Module Syntax in TSConfig

Zhentiw發表於2024-08-13

To fix the CommonJS export issue, we need to make a change to our tsconfig.json file.

Add the verbatimModuleSyntax setting and set it to true:

{
    "compilerOptions": {
        "target": "ES2022",
        "module": "NodeNext",
        "verbatimModuleSyntax": true,
        "esModuleInterop": true,
        "strict": true,
        "skipLibCheck": true,
        "isolatedModules": true,
        "outDir": "./dist"
    }

Over the years, there have been a few attempts to resolve this problem, aiming to make TypeScript stricter about CommonJS exports. The verbatimModuleSyntax setting is the current approach to accomplish this, and it's highly recommended for all tsconfig.json files to ensure cleaner output.

Let's examine the error TypeScript throws if we use a top-level export with verbatimModuleSyntax enabled:

export const example = () => { // red squiggly line under `export`
    return "hello!";
};

// hovering over export shows:
A top-level export modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.

This error message indicates that we shouldn't use the export keyword directly within our .cts files. Instead, we need to refactor our code. First, we remove the top-level export and use export = { example } to properly export the function:

const example = () => {
    return "hello!";
};

export = {
    example
};

Now, the emitted JavaScript code closely mirrors the TypeScript code when it is compiled down to module.exports.

Importing CommonJS Modules

When importing, there is a little bit of a wrinkle to be aware of.

Consider this example:

const iWantToImportThis = () => {
    return "hello!";
};

export = {
    iWantToImportThis,
};

When importing this in a separate file, the syntax is a combination of import and require:

import secondFile = require('./second-file.cjs');

const example = () => {
    return "hello!";
};

secondFile.iWantToImportThis

This unusual syntax is necessary to ensure type safety in CTS modules.

If we were to use a typical const declaration with require, TypeScript would infer the type of secondFile as any since require could potentially return anything. That's why the combined import and require syntax is necessary.

To recap, the verbatimModuleSyntax setting in tsconfig.json enforces proper CommonJS syntax in .cts files. This approach ensures that the emitted JavaScript code closely resembles the TypeScript code, which will make your life easier.

相關文章