{
  "$type": "site.standard.document",
  "canonicalUrl": "https://johnnyreilly.com/posts/typescript-4-7-and-ecmascript-module-support",
  "description": "As part of the TypeScript 4.7 release comes a major upgrade to ECMAScript Module Support for Node.js. This post takes a look at what that means.",
  "path": "/posts/typescript-4-7-and-ecmascript-module-support",
  "publishedAt": "2022-06-07T00:00:00.000Z",
  "site": "at://did:plc:yy3apqjlms24kso7ahn7lbmb/site.standard.publication/3mova7c4nho2b",
  "tags": [
    "typescript",
    "javascript"
  ],
  "textContent": "As part of the TypeScript 4.7 release comes a major upgrade to ECMAScript Module Support for Node.js. This post takes a look at what that means.\n\n\n\nA short history of ECMAScript modules\n\nWhen ES6 shipped back in 2015, with it came the concept of modules for JavaScript. Back then it was known as \"ES6 modules\". These days they are called ECMAScript modules.\n\nWhilst writing code using ECMAScript module semantics came quickly for front end, for the back end (which is generally Node.js) that has not the case. There's a number of reasons for this:\n\n1. There was already an established module system used in Node.js called CommonJS\n2. Node.js itself did not initially offer support for ECMAScript modules; in large part because of the problems associated with being able to support CommonJS _as well_ as ECMAScript modules.\n\nHowever, with the release Node.js 14 support for ECMAScript modules (AKA \"ESM\") landed. If you're interested in the details of that module support then it's worth reading this post on ECMAScript modules.\n\nTypeScript support\n\nThe TypeScript team have been experimenting with ways to offer support for ECMAScript modules from a Node.js perspective, and with TypeScript 4.7 support is being released.\n\nIn this post we'll test drive that support by attempting to build a simple module in TypeScript using the new ECMAScript modules support. As we do this, we'll discuss what it looks like to author ECMAScript modules for Node.js in TypeScript.\n\nLet's go!\n\nMaking a module\n\nWe're going to make a module named greeter - let's initialise it:\n\nWe now have a package.json that looks something like this:\n\nNode.js supports a new setting in package.json called type. This can be set to either \"module\" or \"commonjs\". To quote the docs:\n\n> Files ending with .js are loaded as ES modules when the nearest parent package.json file contains a top-level field \"type\" with a value of \"module\".\n\nWith that in mind, we'll add a \"type\": \"module\" to our package.json.\n\nWe're now ECMAScript module support compliant, let's start adding some TypeScript.\n\nAdding TypeScript 4.7\n\nIn order that we can make use of TypeScript ECMAScript modules support we're going to install TypeScript 4.7 (currently in beta):\n\nWith this in place we'll initialise a TypeScript project:\n\nThis will create a tsconfig.json file which contains many options. We will tweak the module option to be nodenext to opt into ECMAScript module support:\n\nWe've also set the outDir option, such that compiled JavaScript will go into that directory, and the declaration option such that .d.ts files will be generated. We'll also update the \"scripts\" section of our package.json to include build and start scripts:\n\nWriting TypeScript ECMAScript modules\n\nWith all that set up, we're ready to write some TypeScript ECMAScript modules. First we'll write a greetings.ts module:\n\nThere is nothing new or surprising about this; it's just a module exporting a single function named helloWorld. It becomes more interesting as we write our index.ts module:\n\nThe code above imports our helloWorld function and then executes it; writing the output to the console. Not particularly noteworthy. However, the way we import is. We are importing from './greetings.js'. In the past we would have written:\n\nNow we write:\n\nThis can feel slightly odd and unnatural because we have no greetings.js in our codebase; only greetings.ts. The imports we're writing, reflect the code that will end up being executed; once our TypeScript has been compiled to JavaScript. In ES modules relative import paths need to use extensions.\n\nThe easiest way to demonstrate that this is legitimate, is to run the code:\n\nWhich results in:\n\nSo it works!\n\nECMAScript and CommonJS side by side\n\nPart of ECMAScript module support is the ability to specify the module type of a file based on the file suffix. If you use .mjs, you're explicitly saying a file is an ECMAScript module. If you use .cjs, you're explicitly saying a file is an CommonJS module. If you're authoring with TypeScript you'd use mts and cts respectively and they'd be transpiled to mjs and cjs.\n\nHappily Node.js allows ES modules to import CommonJS modules as if they were ES modules with a default export; which is good news for interop. Let's test that out by writing a oldGreetings.cts module:\n\nExactly the same syntax as before. We'll adjust our index.ts to consume this:\n\nNote that we're importing from './oldGreetings.cjs'. We'll see if it works:\n\nWhich results in:\n\nIt does work!\n\nWhat files are emitted?\n\nBefore we close out, it might be interesting to look at what TypeScript is doing when we run our npm run build. It transpiles our TypeScript into JavaScript in our lib directory:\n\nNote the greetings.ts file has resulted in greetings.js and a greetings.d.ts files. Whereas oldGreetings.cts has resulted in oldGreetings.cjs and a oldGreetings.d.cts files; reflecting the different module types represented.\n\nIt's also interesting to look at the difference in the emitted JavaScript. When you consider how similar the source files were. If you look at greetings.js:\n\nThis is the same code as greetings.ts but with types stripped. However, if we look at oldGreetings.cjs we see this:\n\nIn the middle the same code as oldGreetings.cts but with types stripped, but around that boilerplate code that TypeScript is emitting for us to aid in interop.\n\nConclusion\n\nWe've seen what TypeScript support for ECMAScript modules looks like, and how to set up a module to embrace it.\n\nIf you'd like to read up further on the topic, the TypeScript 4.7 beta release notes are an excellent resource.\n\nThis post was originally published on LogRocket.\n\n<head>\n    <link rel=\"canonical\" href=\"https://blog.logrocket.com/typescript-4-7-ecmascript-module-support/\" />\n</head>",
  "title": "TypeScript 4.7 and ECMAScript Module Support"
}