Native TypeScript support in Node for Max (with working example)

Adam Murray's icon

I realized you can run TypeScript code in Node for Max more or less directly, if you run it with Node.js 23, which supports type-stripping from .ts files by default: https://nodejs.org/docs/latest/api/typescript.html#type-stripping .


The only minor snag is you cannot get [node.script] to load .ts files directly. As far as I can tell, it will only load .js and .mjs files. But that's ok: from the entry point file, you can import TypeScript code without doing anything special in Node.js 23.


To get this to work you need to install Node.js 23. You can use the official installer (make sure you select v23) or your preferred alternate installation method. I used Homebrew, so the bin paths will be different for other installations.


I create my Max object like this:

[
  node.script test.mjs
  @node_bin_path /opt/homebrew/bin/node
  @npm_bin_path /opt/homebrew/bin/npm
  @autostart 1 @watch 1
]


The test.mjs (saved next to the .maxpat patcher file) looks like this:

import "./test.ts";
import Max from "max-api";
Max.post("test.mjs successfully imported TypeScript");


And test.ts (in the same folder as the patch and .mjs) looks like:

import Max from "max-api";
const s: string = "From test.ts: TypeScript works natively in Max!";
Max.post(s);


Over in the Max Console:

node.script: From test.ts: TypeScript works natively in Max!
node.script: test.mjs successfully imported TypeScript

Cool. Before upgrading to Node.js 23, it would blow up with an error like "Unable to launch process. Unknown file extension .ts".

Adam Murray's icon

The above approach only works for "erasable types", and means you cannot use things like TypeScript enums. However, with a little extra configuration, that works too.

You need to create the Max object like this (note the addition of the @options attribute)

[
  node.script test.mjs
  @node_bin_path /opt/homebrew/bin/node
  @npm_bin_path /opt/homebrew/bin/npm
  @options --experimental-transform-types 
  @autostart 1 @watch 1
]

And now this will work in the test.ts file:

import Max from "max-api";

enum Color {
  Red = "red",
  Green = "green",
  Blue = "blue",
}
const s: string = "From test.ts: TypeScript works natively in Max!";
Max.post(s, Color.Green);

node.script: [ "From test.ts: TypeScript works natively in Max!", "green" ]

👏