[ANNOUNCE] node-red-contrib-ts – TypeScript Node

Hi everyone,

This is my first post here, so I’m not entirely sure about the usual way of announcing new nodes – apologies if I’m doing it wrong!

I’ve just released a new Node-RED node: node-red-contrib-ts.
It lets you execute TypeScript directly in your flows with:

:white_check_mark: Monaco Editor (same as VS Code, with IntelliSense)
:white_check_mark: Real-time Type Checking
:white_check_mark: Async/Await Support
:white_check_mark: Two Execution Modes – Fast (Function) or Secure (VM)

Full details on GitHub: GitHub Repository

8 Likes

Looks interesting. One thing though, your code examples aren't TypeScript are they? They appear to be standard modern Node.JS? Might be helpful to put in an example that shows a possible benefit of coding in TS rather than JS. :smiley:

Thanks for the feedback! That’s a great point – the current examples are indeed quite close to modern JavaScript. I’ll add an example that highlights a real benefit of using TypeScript, such as explicit typing and IntelliSense/autocomplete support.
I’ve also just updated the node so the editor now properly analyzes TypeScript during editing, with real-time type checking.

1 Like

Of course, both of these can be dealt with using JavaScript and JSDoc comments. :smiley: So not unique to TS.

Also, I've found some areas of TS IntelliSense is pretty appalling. DOM API's being a particular case in point.

You’re right, JSDoc helps, but TypeScript goes much further:
:white_check_mark: Strict type checking before execution
:white_check_mark: Native support for interfaces and custom types
:white_check_mark: Full interoperability with Node.js and external libraries

With version 1.1.0, the editor now properly analyzes TypeScript with real-time type checking, just like in VS Code. This makes the benefits much clearer in Node-RED.

2 Likes

Here’s a quick example to show the difference:

Without TypeScript (no error detected):

With TypeScript (error detected in real-time):

1 Like

What if you update the core node to add a flag that would enable typescript?

1 Like

I would add a new tab where users can configure json schemas for the msg and config objects. These schemas are turned automatically into types which are injected in monaco. With this, Users can type msg. and monaco will show them the props available in msg or config objects. Why using schemas and not just types directly? Because typescript alone doesnt validate data at runtime. With json schemas you can run a validation before handing the data over to the node.

Use ajv + typebox instead of zod for runtime validations because it is faster.

You can take a look how runtime validation can be done with ajv here GitHub - AllanOricil/node-red-vue-template: Write Node-RED nodes using Vue and Typescript

1 Like

Apologies for seemingly being a bit argumentative. I'd just like people to recognise both the strengths and weaknesses of JS vs TS.

Are you running the node through a TS compiler? I know that Node.js is introducing "native" TS execution but I believe that they are "simply" (not actually simple at all I'm sure) removing the type annotations at execution time?

Not sure about interface definitions. Personally, I've always found those to get in the way rather than help but then I have never been a professional JS/TS programmer in an enterprise environment where I think that they might actually be helpful rather than just an overhead.

Custom types can, of course, be defined in JSDoc quite easily.

Would you mind explaining this one? I'm not sure what you mean.

This is certainly easier to do in TS than with JSDoc, that's for sure.

This should work, it works in VS Code:

/**
 * @typedef {object} Page
 * @property {string} path - File path of the page
 * @property {string} name - Generated name of the page (format: "pagesN.jpg")
 * @property {number} width - Width of the page in pixels
 * @property {number} height - Height of the page in pixels
 * @property {number} bytes - Size of the page in bytes
 * @property {string} type - MIME type of the page (always "image/jpeg")
 */

const pages = (msg.payload)
    .filter( l => 1.trim())
    .map( (line, i) => {
        const [path, width, height, size] = line.split(' ; ')
        /** @type {Page} */
        return {
            path,
            name: `pages${i + 1}.jpg`,
            width: Number(width),
            height: Number(height),
            bytes: Number(size),
            type: 'image/jpeg'
        }
    })

pages[0].name = 2

In VS Code it does give the realtime error. But I think it only works there because it needs the ESLINT extensions and config.

Urm, actually, you don't need the type definition, it works without as long as ESLINT is configured correctly.

That seems like an interesting idea.

1 Like

If the Node-RED team wants to integrate this approach into the core function node, they
can reuse my code - it's open source and modular.

2 Likes

users can configure json schemas for the msg and config objects

Excellent idea! I love the approach of JSON schemas → automatic TypeScript types.

Use ajv + typebox instead of zod for runtime validations because it is faster.

I'll study Allan Oricil's GitHub reference and explore how to integrate this cleanly into a configuration tab.

Thanks for this very insightful technical suggestion! :rocket:

1 Like

No worries about being argumentative - these are excellent technical questions!

Maybe add both options? Let users choose between:

  • TypeScript mode (what I have now)
  • JSDoc mode (with ESLINT is configured correctly)

Yes, I'm using TypeScript's transpiler (with cache) to compile TS → JS before execution. The type checking happens at "design time" in Monaco, not runtime.

TypeScript has excellent support for Node.js built-ins and npm packages through @types/* packages. For example: fs, path, crypto etc. are fully typed. Many libraries are coded in typescript, we can copy TS or JS into node script input without conversion.

Thx

2 Likes

That’s the point. If you add TypeScript support you can still code with JavaScript. It is becoming like a standard, it gives a better DX (sorry but JSDoc does not give the same DX, it is verbose compared to TypeScript). I don't know why there is still discussion about TypeScript or not. Even NodeJS is in the process to accept TypeScript. It is like trying to put doors on the field...

3 Likes

Maybe because TS is twice the work for most things. More like having to code in C++ and if you are going to do that, you might as well do it. I don't want to have to generate 2 files for every 1 that I create in JS.

Neither do I want to have to do a build every time I change something.

But they aren't really, are they. They are simply type stripping and so turning it back into JavaScript again in a rather brute-force way.

As I say, TS certainly has some advantages in certain circumstances. But I would argue that probably by far the majority of Node-RED users - even the majority of custom node creators - do not know or need or want TS.

The whole point - for me - of sticking with a tool like Node-RED is that it uses the same language as the web does. That was why I switched from PHP to Node.js for back-end programming in the first place. I am not a professional, full-time developer and I don't want all the overheads of TS.

If ever Node-RED switched to only TS, I would leave the platform as a node developer. What's more, it is already hard enough to contribute to core, TS would make that bar even higher for most of us.

That isn't to say that some parts of NR might not benefit from some TS love - I expect they might. Just that it feels extremely important to me that JavaScript developers are not crowded out by TS.

1 Like

By parts:

You are not generating, it is a tool which makes this by you. Like when you uses babel / swc, etc

It is almost transparent and it gives you errors feedback

They are doing just the first step, but they are on the way to support TS because if not the runtime will be old fashioned compared to the alternatives (Deno and Bun). Like CJS and ESM, Node said it was impossible to mix then because one is sync and the another is async and surprise surprise, they found a way to make it possible because ESM is the standard and the other alternatives make you transparent and painless.

I don't buy that. TypeScript is a superset of JS, not another language. The learning curve is almost flat, because is JavaScript with more "optional" features, because in a TypeScript you can code just with JavaScript. But if you add types and more features it only gives better developer experience to users, because you have better autocomplete, better error feedback, etc. Even for just regular users, they are going to have a better experience coding.

TypeScript is JavaScript...

Your experience does not said that

Almost nothing and most devs don't have to be worried, only if you need a performantic code (which is not your case because you said you are not a professional full-time developer)

Start saying that and not

Au contraire, because as I said many times, TypeScript is JavaScript + it forces you to have a better and readable code (could you do a mess in TS? Of course, but it is harder than in JS because you have a compiler telling a ton fo things you are doing wrong).

Most JavaScript developers are switching to TypeScript because they are no crowded out by it. Actually you are adding a better experience to code in JavaScript. TypeScript is not another language, is a superset of JavaScript. In a TypeScript file you can just type JavaScript is completely fine. Let the user choose. If TypeScript support is added you are not wiped out by it, you can still code just in JavaScript, not adding TS is a way wiped out people.

Those reasons before are tough to buy because they didn't represent the real world. They sound more like a barrier which hide another real reasons like the language (TS) it is owned by a "not so good / ethical company" or kind of. Reasons which may have sense (and probably I agree with them) but the state of the art is the state of the art.

TypeScript is the present in the JavaScript ecosystem. Like the wave of JavaScript tooling made with Rust. Being against that is putting the pavement to make Node-RED a stagnant tool.

1 Like

Congratulations @benoitadam

I have demanded to index your repo in DeepWiki. Now it is indexed (I hope you don't mind)

2 Likes

I'm not here to argue. I have put across my points and made my position clear.

1 Like

I liked this DeepWiki! I tried with one of my complex repos and it didnt work that well. It doesn't understand c/c++ files apparently

1 Like