1

The goal: to import a local .ts ESM module from a REPL. Here's a reproducible project.

I'm using ESM modules and have "type":"module" set in package.json. Currently using ts-node (v10.9.1) but open to alternatives. What settings should I have in tsconfig.json, and/or elsewhere, to make any of the following work?

import sql from './db.js'
import sql from './db.ts'
await import('./db.ts')
await import('./db')
// etc.; I'll take anything :)

tsconfig.json:

{
  "include": [ "src" ],
  "exclude": [ "node_modules", "dist" ],
  "ts-node": {
    "transpileOnly": true,
    "esm": true,
    "experimentalSpecifierResolution": "node"
  },
  "compilerOptions": {
    "lib": ["es2023"],
    "module": "Node16",
    "target": "es2022",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "nodenext"
  }
}

For a specific example, I'm importing 'postgres' library in this db.ts file:

import postgres from 'postgres'
const sql = postgres('localhost:5432',{
  host                 : process.env.DB_HOST,
  port                 : Number(process.env.DB_PORT),
  database             : process.env.DB_NAME,
  username             : process.env.DB_USER,
  password             : process.env.DB_PASS,
})
export default sql

And foo.ts merely contains a toy query:

import sql from './db.js'
console.log(await sql`select starelid from pg_statistic limit 1`);

This works and can be called as: set -a && source ./.env && ts-node src/foo.ts

How can I import either of the two .ts files from ts-node or other REPL?


A 'dynamic import' sadly errors as well.

With .ts extension:

ts-node
> foo = await import('./src/foo.ts')
Uncaught SyntaxError: 
export {};
^

'import' and 'export' may only appear at the top level

Without .ts extension:

> foo = await import('./src/foo')
Uncaught:
TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]: A dynamic import callback was not specified.
    at Object.execCommand (/Users/me/.asdf/installs/nodejs/18.16.0/lib/node_modules/ts-node/src/repl.ts:633:32)
    at runInContext (/Users/me/.asdf/installs/nodejs/18.16.0/lib/node_modules/ts-node/src/repl.ts:673:19)
    at Script.runInThisContext (node:vm:129:12)
    at /path/to/project/<repl>.ts:3:4
    at /path/to/project/<repl>.ts:1:18
    at importModuleDynamicallyCallback (node:internal/process/esm_loader:39:9)
    at new NodeError (node:internal/errors:399:5)
    at __node_internal_captureLargerStackTrace (node:internal/errors:490:5) {
  code: 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING'
}

Ricardo had an almost identical question (and I also can't figure out how the answer to this question should work, if at all).

1 Answers1

0

It should work out of the box in ts-node, at least if you omit the .ts extension in the import. If you don't, you'll get an error that tells you about it and also tells you the two solutions: either omit .ts or enable the allowImportingTsExtensions setting.

$ ts-node
> import { bar } from './foo.ts'
<repl>.ts:4:21 - error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.

4 import { bar } from './foo.ts'
                      ~~~~~~~~~~

> import { bar } from './foo'
undefined
> bar()
hello world
undefined
>

An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • Thanks so much for helping out a helpless TS newbie! Sadly, I get (different) errors either _with_ or _without_ `.ts` extension, as seen in my updated question (along with full `tsconfig.json`). I'll prepare an example repo. – VanillaDonuts Jun 08 '23 at 11:56
  • I've added [an example repo, reproducible with only 3 commands](https://github.com/oatmealb/ts-node-repl-import). – VanillaDonuts Jun 08 '23 at 12:43