Using TypeScript to write JSR223 Scripts

Hello everyone,
here’s a little example demonstrating how one can use TypeScript to write openHAB Scripts.

All this essentially does is use rollup with its typescript plugin to generate a single javascript file in the IIFE format.

In addition to that, this is passed to the generated bundle, so it can be used in the Script.
This happens in the package.json

TypeScript defaults to ES5. Considering that Nashorn’s implementation implements ES5.1, no typescript config should be needed.

There is probably a couple of things that could be improved (for example handling this better). If you have any improvements, please let me know.

The example in the template generates a .js that looks like this :
As the files might change in the future: this is the commit that resulted in the file below.

var ctx = this;
(function () {
    'use strict';

    var LoggerFactory = /** @class */ (function () {
        function LoggerFactory() {
        LoggerFactory.getByRuleId = function (ruleId) {
            // TypeScript does not know about Java. It does not know that this script will be run in Nashorn. 
            // As such, it will complain about Java being undefined. 
            // To fix this, references to "unknown" variables that are available in the script must be 
            // annotated with a @ts-ignore.
            return Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.rule." + ruleId);
        return LoggerFactory;

    // This is the "main" file. Import modules into here.
    // While the following statement will function correctly when uncommented, 
    // it is discouraged to use "this" directly in the root scope.
    this.logger = typeof this.logger === "undefined" ? LoggerFactory.getByRuleId("myRuleId") : this.logger;
    // Instead store this in a variable. That way you can add an interface to the variable which will help with autocompletion.
    var _this = ctx;
    _this.logger = typeof _this.logger === "undefined" ? LoggerFactory.getByRuleId("myRuleId") : _this.logger;
    // This will be an object"Type of this.Java is {}", typeof _this.Java);
    // You can use templating here too. logger references the Java class."Hello, {}!", "World");
    // items was declared in openHabRoot.ts
    var allItems = _this.itemRegistry.getItems();
    // Note that you do not have to prepent _this in front of Java, itemRegistry, etc. TypeScript will just complain about it.
    //@ts-ignore"Is _this.itemRegistry instanceof ItemRegistry? : {}", _this.itemRegistry instanceof Java.type("org.openhab.core.items.ItemRegistry"));"There are {} items.", allItems.size());


EDIT: Moved repository from gitlab over to github

1 Like

Unfortunately, this approach seems not to work for not-compiled scripts. And it does not work for all types of lambdas (functional interfaces). I did some experiments, but could not find a pattern yet what works and what not. It is for sure that functional interfaces that define a method throwing a checked exception do not work this way. Also if the functional interface is not public but a private inner interface.

Unfortunately, this approach seems not to work for not-compiled scripts

What’s meant with “not-compiled” here?

I did some experiments, but could not find a pattern yet what works and what not.

I have found that wrapping the Functions inside a lambda works, as in… instead of doing this:

this.someCallback = someFunction 


this.someCallback = () => { someFunction() }

But this should only really be necessary when invoking Java-Methods, no?

I have set up a basic example here:

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.