Skip to main content

Javascript Runtime Limitations

Hosanna brings JavaScript and TypeScript to Roku, but due to the underlying BrightScript environment, some features are not fully supported or may behave differently. Below is a summary of current limitations and recommended workarounds.


Unsupported Features

Call Expressions

  • parseInt does not support hexadecimal (0x10) or binary (0b10) string input. Use parseInt("10", 16) or parseInt("10", 2) instead.
  • isFinite returns true for numbers, false otherwise.
  • isNaN returns true for numbers, false otherwise.
  • parseFloat may not support scientific notation—please verify for your use case.

Identifier Expressions

  • Infinity and NaN are not supported.

Math Functions

  • Some math functions may behave differently from JavaScript, especially for edge cases and less common functions.
  • Math.acos(-1) does not work.
  • Math.fround does not work correctly.
  • Math.atan2 truncates results to 4 decimal places.

Console

Only the following methods are implemented:

  • log
  • error
  • warn
  • info
  • debug
  • trace

Logging arrays: You cannot log an inline-declared array after a string due to BrightScript limitations:

// Does not work
console.log("text", ["inline array"]);

// Works
console.log(["inline array"], "text");

Object Functions

Object.keys / Object.values / Object.entries

  • These methods do not support strings, the prototype chain, or arrays.

Other Object Functions

  • Some object utility functions are only partially supported and may not behave exactly as in JavaScript.

Array

Instance Methods

  • Array.prototype.push does not return the new length for a simple push (for performance reasons); it is slow for variadic arguments but does return the length in that case.
  • Array.prototype.unshift only supports adding a single item and does not return the new length.
  • Array.prototype.concat does not flatten nested arrays:
    [1,2,3].concat([4, 5], [6, 7]) // => [1, 2, 3, [4, 5], [6, 7]]
  • Array.prototype.join is currently slow; future versions may optimize this for string arrays.

String

  • String.prototype.codePointOf and normalize are not implemented.

Closures

Supported:

  • Updating instance variables, getters/setters, and module variables.

Not Supported:

  • Updating closure-captured variables that are not instance or module variables. To work around this, wrap the variable in an object and capture that object:
    const foo = () => {
    let captured = { value: 0 };
    return () => {
    captured.value++;
    console.log(captured.value);
    };
    };
  • Immediately Invoked Function Expressions (IIFE) are not supported. Instead, declare a function and call it immediately:
    const foo = () => { }; foo();
  • Capturing getters and setters is not supported.

Function Pointers

Not Supported:

  • Passing a function pointer to a global function that is not in a module.
  • Assigning a function to an anonymous object (declare locally, assign, and bind instead).

Supported:

  • Passing function pointers to global functions declared in a module, class instance methods, or locally declared functions.
  • Binding function pointers as expected.

Operators

Spread

  • You cannot spread strings into objects, or spread anything with a type declaration.

|| for Assignment

  • The || operator is not always reliable for assignment and can be slow; prefer using ?? instead:
    let a = b ?? 4;
  • Chained assignments using || may not transpile correctly; split them into multiple lines if you encounter issues.

Modules and Imports

Not Supported:

  • Importing non-TypeScript files (such as text, XML, or JSON).
  • Exporting something before importing it.
  • Using export default.

Example:

// BAD
export { DebugMenuViewStruct, DebugMenu };
import { DebugMenuViewStruct, DebugMenu } from './DebugMenu-generated-struct';

// GOOD
import { DebugMenuViewStruct, DebugMenu } from './DebugMenu-generated-struct';
export { DebugMenuViewStruct, DebugMenu };

Equivalence

  • Deep equality is limited; object equivalence only works if objects implement IIdentifiable (using the _hid field).
  • Enums are supported only if all enum values are of the same type.
  • If the type cannot be properly inferred, you will receive a transpiler warning. For better performance, cast unknown types before checking equality.

Example:

// If `field` is a union or unknown type, it may not be properly inferred, and will use slow equality checks.
if (field === 'translation') { ... }

// This will use fast equality checks, as it casts `field` to a string.
if ((field as string) === 'translation') { ... }

Types, Booleans, and Truthiness

  • Union types with booleans will always resolve to boolean.
  • Casting arrays to booleans is not supported.

Example:

const source: any[] = ['yes', 0, null];
const v: boolean[] = source; // Not supported

Type Philosophy: Types are enforced at declaration, assignment, and invocation. Variables are marshalled to the expected type at the point of use.

Framework Limitations

  • Importing JSON files is not supported, as it can impact performance. Instead, use code such as const debugFlags = JSON.parse(ReadAsciiFile('pkg:/assets/meta/debug-flags.dev.json')).

Class

Not Supported:

  • Declaring classes inside functions.
  • Having two classes with the same name anywhere in the codebase.

Date

The native JavaScript Date object is not supported in Hosanna. Instead, you should use the drop-in replacement HsDate, which provides similar functionality and is designed to work reliably in the Roku/BrightScript environment.

Intervals and Timeouts

setInterval and setTimeout are supported in Hosanna. However, you cannot use Node.js-style return types for their handles. The recommended way to declare variables for interval or timeout handles is:

private debounce?: ReturnType<typeof setTimeout>;

This ensures compatibility with the Hosanna runtime and avoids type errors.