The Verbatim Module Syntax in TSConfig
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, "esModule
Transcript
00:00 Okay, the way that we properly source this error is we dive into the tsconfig.json and we uncomment or we pull out verbatim module syntax true. There have been a few kind of efforts over the years to try to fix this issue, to basically make TypeScript more strict about this,
00:16 and verbatim module syntax is the current new hotness for how to do it. And this is why I recommend it in every tsconfig.json because fake_esm here is a little bit gross. Really the thing that we're getting out here, if we look inside dist, yeah we get this sort of funky object defined property. We really just want to say module.exports
00:36 equals example. This kind of outputted fake_esm is pretty gross. So, and the error that we're getting here by the way, a top level export modifier cannot be used on value declarations in a common js module when verbatim module syntax is enabled. Basically saying don't use exports in here because we've got verbatim module syntax
00:56 enabled. So we can now remove the export but we still need to export it right. So we can use export equals example. And now if we look at the outputted JavaScript here it's actually much simpler and represents our TypeScript a lot better. So we look here we've got on the left
01:14 the output JavaScript and on the right we've got the TypeScript. It's pretty much identical except for export equals sort of compiling down to module.exports. So I recommend if you have these TypeScript files these CTS files in your repo you use this setup. There is a little
01:34 wrinkle here which is that the way you import stuff is pretty funky. You can use a require call. So if I just create a new file here I'm just going to get rid of all this stuff. So this is an example copy.
01:46 Let's imagine that I've got I want to import this and then I can export that. I want to import this. So now that is in my second file and I go into my example.cts here and if I
02:04 want to pull this in let's say I want to import this then it uses this really funky syntax. So we've got import second file equals require second file.cjs. Look at that. It's an import combined with a require. This is TypeScript's method for using
02:22 require inside CTS modules. If we just said const second file equals require we actually get an error where second file is typed as any. Because require is just a function that could return anything TypeScript sort of bails out of doing this and so if you want
02:40 type safety here then you need to use this funky syntax of import second file equals require. So this is how you manage .cts files if for whatever reason you need to just have a bit of if you're using like emitting CommonJS or if you just
02:57 need a little bit of CommonJS sprinkled into your otherwise ES module project. I recommend having verbatim module syntax on and using this specific syntax for compiling down to require calls because as we see here so if we look at example.cgs that's outputted it means that the code that gets emitted
03:17 is so similar to the code that you're actually writing, which is really, really important.