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
parseIntdoes not support hexadecimal (0x10) or binary (0b10) string input. UseparseInt("10", 16)orparseInt("10", 2)instead.isFinitereturnstruefor numbers,falseotherwise.isNaNreturnstruefor numbers,falseotherwise.parseFloatmay not support scientific notation—please verify for your use case.
Identifier Expressions
InfinityandNaNare 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.frounddoes not work correctly.Math.atan2truncates results to 4 decimal places.
Console
Only the following methods are implemented:
logerrorwarninfodebugtrace
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.pushdoes 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.unshiftonly supports adding a single item and does not return the new length.Array.prototype.concatdoes not flatten nested arrays:[1,2,3].concat([4, 5], [6, 7]) // => [1, 2, 3, [4, 5], [6, 7]]Array.prototype.joinis currently slow; future versions may optimize this for string arrays.
ReadonlyArray
- TypeScript's
ReadonlyArray<T>is not supported. UseArray<T>instead. - If you need immutability semantics, avoid mutating arrays in code paths or create shallow copies.
String
String.prototype.codePointOfandnormalizeare 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_hidfield). - 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.
Numeric Types: Long Integers
Roku BrightScript models 64-bit long integers distinctly from 32-bit integers using the & type designator. JavaScript/TypeScript has only number (IEEE-754 double), so Hosanna provides a branded type to bridge the gap:
export type roLongInteger = number & { __brand: 'roLongInteger' };
- Values typed or cast as
roLongIntegerare emitted with BrightScript's&suffix in variables, fields, params, arrays, and object/record values. - Regular numbers are not modified and do not get
&.
Hosanna cannot automatically detect when a value must be a BrightScript long integer. For correctness (especially for values > 2,147,483,647) annotate or cast to roLongInteger.
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.