Skip to content

tmythicator/ob-ts-node

Repository files navigation

ob-ts-node

https://melpa.org/packages/ob-ts-node-badge.svg https://github.com/tmythicator/ob-ts-node/actions/workflows/test.yml/badge.svg https://img.shields.io/badge/Built_with-Nix-5277C3.svg?style=flat-square&logo=nixos&logoColor=white

Org Babel support for Typescript via ts-node

This package adds Org-Babel support support for evaluating typescript (and ts alias) code blocks using using ts-node. Unlike ob-typescript, ob-ts-node works seamlessly with Node.js CommonJS-style imports.

Example

#+BEGIN_SRC typescript :cli-args "--transpile-only"
  const https = require('https');

  https.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY', (resp) => {
      let data = '';

      // A chunk of data has been recieved.
      resp.on('data', (chunk) => {
          data += chunk;
      });


      resp.on('end', () => {
          console.log(JSON.parse(data).title);
      });

  }).on("error", (err) => {
      console.log("Error: " + err.message);
  });
#+END_SRC
#+RESULTS:
: Leopard Spots on Martian Rocks

Note: Unlike Elisp, external languages only return results via stdout. To capture values, you must console.log them.

Status [2/3]

The project is more or less in beta. But still, one can benefit from using it.

  • [X] Basic support for evaluation
  • [X] Better support for customization
  • [ ] Support for `:session`

Installation

Using use-package and quelpa packages (recommended):

(use-package ob-ts-node
  :ensure t
  :after org
  :config
  (ob-ts-node-setup)
  (add-to-list 'org-babel-load-languages '(ts-node . t))
  (org-babel-do-load-languages 'org-babel-load-languages
                               org-babel-load-languages)
  :custom
  (ob-ts-node-tsconfig "~/.config/ts-node/tsconfig.json")) ;; Recommended to pin `tsconfig.json`

Manual:

(add-to-list 'load-path "/path/to/ob-ts-node.el")
(require 'ob-ts-node)
(ob-ts-node-setup)
(add-to-list 'org-babel-load-languages '(ts-node . t))
(org-babel-do-load-languages 'org-babel-load-languages
                             org-babel-load-languages)
(setq ob-ts-node-tsconfig "~/.config/ts-node/tsconfig.json")

Node.js dependencies:

npm i -g node typescript ts-node

Configuration

Recommended: pin a tsconfig.json, as shown in Installation section. ts-node is sensitive to compiler options. For predictable behavior across Babel blocks, use a project config (per “via tsconfig.json (recommended)”). Minimal config you can copy:

{
    "compilerOptions": {
        "target": "ES2022",
        "module": "NodeNext",
        "moduleResolution": "NodeNext",
        "strict": true,
        "esModuleInterop": true
    }
}

Note: Set strict to false to evade type-errors for easier scenarios

Header arguments

  • :cli-args: Extra flags passed to ts-node:
    #+BEGIN_SRC typescript  :cli-args "--skip-project"
    // your code goes here
    #+END_SRC
        

    Note: If ob-ts-node-tsconfig is set, using --skip-project will automatically suppress the injection of that config file. Warning: When skipping the project file, you may need to provide compiler options manually if your environment defaults don’t match the code style (e.g. CommonJS vs ESM):

    :cli-args "--skip-project --compiler-options '{\"module\":\"commonjs\"}'"
        
  • :cli-override: Completely override the arguments:
    #+BEGIN_SRC typescript :cli-override "-v"
      console.log(43)
    #+END_SRC
    
    #+RESULTS:
    : v9.1.1
        
  • :cli-cmd Override the command entirely (default is ts-node, customizable via ob-ts-node-command):
    #+BEGIN_SRC ts :cli-cmd "npx tsx"
    console.log("Using tsx");
    #+END_SRC
    
      #+RESULTS:
    : Using tsx
        

Use other execution engines (tsx / bun / deno)

You can swap the runner via :cli-cmd and keep the same Org-Babel flow.

  • tsx (zero-config TS/ESM runner)
    #+BEGIN_SRC typescript :cli-cmd "npx tsx"
    console.log("Using npx tsx");
    #+END_SRC
    #+RESULTS:
    : Using npx tsx
        
  • bun (fast JS/TS runtime)
    #+BEGIN_SRC typescript :cli-cmd "npx bun run"
    console.log("Hello from bun");
    #+END_SRC
    #+RESULTS:
    : Hello from bun
        
  • deno (secure runtime; add permissions if needed)
    #+BEGIN_SRC typescript :cli-cmd "npx deno run"
    console.log("Deno here");
    #+END_SRC
    #+RESULTS:
    : Deno here
        

Compatibility

  • Emacs >= 25.1 (for alist-get), Org >= 8.0
  • Emacs >= 29 uses typescript-ts-mode; older Emacs falls back to typescript-mode; otherwise js-mode.

Troubleshooting

#1 Unpredictable results? Pin your tsconfig.json (most common)

If tsconfig.json isn’t found from the execution directory, ts-node falls back to internal defaults. Fix: place a project tsconfig.json in the repo root or set ob-ts-node-tsconfig to a known file. Quick sanity checks:

ts-node --showConfig

Missing @types/node dependency

error TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.

Solution:

npm i --save-dev @types/node

Parameter “x” implicitly has ‘any’ type

error TS7006: Parameter 'resp' implicitly has an 'any' type.

Solution: use :cli-args "--transpile-only" in babel header

About

Literate programming in Typescript made easy

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published