With module: "nodenext", TypeScript enforces Node's real ESM resolver, which does not do extension guessing. A relative import without an extension produces error TS2835: Relative import paths need explicit file extensions in ECMAScript imports; did you mean './util.js'?.
The extension you write is the one that will exist at runtime, which is the compiled .js, even though the file on disk during development is .ts. Writing ./util.ts gets error TS5097 unless allowImportingTsExtensions is set, and that flag itself requires noEmit or emitDeclarationOnly because the compiler will not rewrite the specifier.
TypeScript 5.7 added rewriteRelativeImportExtensions, which lets source files import ./util.ts and emits ./util.js. That combination is what makes one source tree work both under node --experimental-strip-types and under a normal tsc build. Whichever route you pick, apply it consistently, because a single missing extension only fails at runtime with ERR_MODULE_NOT_FOUND.