Skip to Content
Course content

91: Target and Module Settings Explained

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've noticed a recurring pattern when I'm reviewing PRs from developers moving to TypeScript: there is a persistent belief that the target setting in your tsconfig.json is what tells TypeScript which version of the language it should use to validate your code. People often think, "If I set target to ES5, I can't use arrow functions in my source code because ES5 doesn't support them."

That is completely wrong. And it's a distinction that will save you hours of head-scratching if you get it straight now.

"Target" is for the Runtime, Not the Compiler

The TypeScript compiler (tsc) is designed to let you use the latest and greatest ECMAScript features regardless of where your code eventually runs. The target setting doesn't restrict what you can write; it defines what the output looks like.

Let's look at a real example. Suppose you write this modern snippet:

async function getUserData(id: string) {
    const response = await fetch(`/api/users/${id}`);
    return response.json();
}

If you set "target": "ESNext", the compiled JavaScript will look almost identical to the code above because modern browsers and Node.js versions support async/await natively. But if you change that to "target": "ES5", TypeScript will "downlevel" that code. It will transform that sleek async function into a bulky mess of state machines and helper functions (using __awaiter and __generator) so that it can run in Internet Explorer 11 without crashing.

I'll be honest: downleveling has a cost. It makes your output files larger and slightly slower. My rule of thumb? Set your target to the lowest version of JavaScript that your actual users' browsers (or your server's Node version) can execute.

The "Module" Setting Isn't About Your TS Imports

This is where things get truly confusing. You're already using import and export in your TypeScript files, so you might assume the module setting is just telling TypeScript that you're using modules. It's not.

The module setting tells TypeScript how to rewrite those imports and exports in the generated JavaScript. This is critical because the JavaScript ecosystem is split between different module systems: CommonJS (used by older Node.js) and ESM (the official JavaScript standard used by browsers and newer Node.js).

If you use "module": "CommonJS", your import { User } from './models' becomes const models_1 = require("./models"). If you use "module": "ESNext", it stays as an import statement.

Here is the trap: if you set "module": "ESNext" but try to run that code in a Node.js environment that isn't configured for ESM (missing "type": "module" in package.json), Node will throw a SyntaxError: Unexpected token 'export'. The code is valid JavaScript, but it's the wrong flavor of JavaScript for that specific environment.

Matching Settings to Your Environment

Because target and module are independent, you can mix and match. You might want to target ES6 (to get classes and arrow functions) but use CommonJS modules (because your legacy Node server requires require()).

When I start a new project, I usually follow this logic:

  • Building a modern web app (Vite/Webpack): I usually go with target: "ESNext" and module: "ESNext". I let the bundler handle the final compatibility.
  • Building a Node.js library: I often stick with module: "CommonJS" to ensure the widest possible compatibility with other npm packages.
  • Building for legacy browsers: target: "ES5" is the old reliable, though ES6 is generally safe for almost everything today.



📋 Practical Task

Fixing the 'Unexpected token export' Error in Node.js

You are tasked with fixing a small Node.js utility project. The project is intended to run on an older version of Node.js that only supports CommonJS, but the current TypeScript configuration is outputting ES Modules, causing the app to crash on startup.

The current tsconfig.json:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "ESNext",
    "outDir": "./dist",
    "strict": true
  }
}

The source code (src/index.ts):

export const greet = (name: string) => `Hello, ${name}!`;
console.log(greet("Developer"));

The Goal: Modify the tsconfig.json so that when the code is compiled, the export keyword is converted to module.exports (CommonJS), allowing it to run in the legacy Node environment without changing any of the TypeScript source code.

Instructions:

  1. Identify which setting is causing the SyntaxError in Node.js.
  2. Update the tsconfig.json to the correct module system.
  3. Explain why changing target wouldn't solve this specific "Unexpected token export" issue.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.