Skip to content

ES5 Helper Reference

Overview

When writing TypeScript scripts in expressCode, your code is automatically transpiled to ES3-compatible ExtendScript. However, After Effects' ExtendScript engine (based on ES3) doesn't support many useful ES5 array and string methods.

expressCode solves this by:

  1. Transforming modern method calls into helper function calls
  2. Prepending non-polluting helper functions to your script

This allows you to write modern JavaScript while maintaining compatibility with After Effects' ES3 engine.

How It Works

Transformation Process

When you write TypeScript code using ES5 methods:

typescript
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);

expressCode automatically transforms it to:

javascript
var numbers = [1, 2, 3, 4, 5];
var doubled = __es5_map(numbers, function(n) { return n * 2; });
var evens = __es5_filter(numbers, function(n) { return n % 2 === 0; });

The helper functions (__es5_map, __es5_filter, etc.) are then prepended to your script.

Non-Polluting Approach

Unlike some polyfill approaches that modify global prototypes (Array.prototype.map), expressCode uses standalone helper functions. This:

  • Avoids conflicts with existing code
  • Prevents prototype pollution
  • Maintains script isolation
  • Ensures consistent behavior

Supported Methods

Array Methods

map(callback, thisArg?) - Creates a new array with transformed elements

Creates a new array with the results of calling a function on every element.

TypeScript:

typescript
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// Result: [2, 4, 6]

Transforms to:

javascript
__es5_map(numbers, function(n) { return n * 2; })

Implementation:

javascript
function __es5_map(arr, callback, thisArg) {
    var len = arr.length >>> 0;
    var result = new Array(len);
    for (var k = 0; k < len; k++) {
        if (k in arr) {
            result[k] = callback.call(thisArg, arr[k], k, arr);
        }
    }
    return result;
}
filter(callback, thisArg?) - Creates a new array with elements that pass a test

Creates a new array with elements that pass a test.

TypeScript:

typescript
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0);
// Result: [2, 4]

Transforms to:

javascript
__es5_filter(numbers, function(n) { return n % 2 === 0; })

Implementation:

javascript
function __es5_filter(arr, callback, thisArg) {
    var len = arr.length >>> 0;
    var result = [];
    for (var k = 0; k < len; k++) {
        if (k in arr) {
            var val = arr[k];
            if (callback.call(thisArg, val, k, arr)) {
                result.push(val);
            }
        }
    }
    return result;
}
forEach(callback, thisArg?) - Executes a function for each array element

Executes a function once for each array element.

TypeScript:

typescript
const layers = comp.layers;
layers.forEach((layer, index) => {
  layer.name = "Layer " + (index + 1);
});

Transforms to:

javascript
__es5_forEach(layers, function(layer, index) {
  layer.name = "Layer " + (index + 1);
})

Implementation:

javascript
function __es5_forEach(arr, callback, thisArg) {
    var len = arr.length >>> 0;
    for (var k = 0; k < len; k++) {
        if (k in arr) {
            callback.call(thisArg, arr[k], k, arr);
        }
    }
}
reduce(callback, initialValue?) - Reduces array to a single value

Reduces an array to a single value by executing a reducer function.

TypeScript:

typescript
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, n) => acc + n, 0);
// Result: 10

Transforms to:

javascript
__es5_reduce(numbers, function(acc, n) { return acc + n; }, 0)

Implementation:

javascript
function __es5_reduce(arr, callback, initialValue) {
    var len = arr.length >>> 0;
    var k = 0;
    var value;

    if (arguments.length >= 3) {
        value = initialValue;
    } else {
        while (k < len && !(k in arr)) k++;
        if (k >= len) {
            throw new TypeError('Reduce of empty array with no initial value');
        }
        value = arr[k++];
    }

    while (k < len) {
        if (k in arr) {
            value = callback(value, arr[k], k, arr);
        }
        k++;
    }
    return value;
}
reduceRight(callback, initialValue?) - Reduces array from right to left

Same as reduce, but processes the array from right to left.

TypeScript:

typescript
const numbers = [1, 2, 3, 4];
const result = numbers.reduceRight((acc, n) => acc + n, 0);
// Result: 10

Transforms to:

javascript
__es5_reduceRight(numbers, function(acc, n) { return acc + n; }, 0)

Implementation:

javascript
function __es5_reduceRight(arr, callback, initialValue) {
    var len = arr.length >>> 0;
    var k = len - 1;
    var value;

    if (arguments.length >= 3) {
        value = initialValue;
    } else {
        while (k >= 0 && !(k in arr)) k--;
        if (k < 0) {
            throw new TypeError('Reduce of empty array with no initial value');
        }
        value = arr[k--];
    }

    while (k >= 0) {
        if (k in arr) {
            value = callback(value, arr[k], k, arr);
        }
        k--;
    }
    return value;
}
indexOf(searchElement, fromIndex?) - Returns first index of element

Returns the first index at which an element can be found.

TypeScript:

typescript
const colors = ["red", "green", "blue"];
const index = colors.indexOf("green");
// Result: 1

Transforms to:

javascript
__es5_indexOf(colors, "green")

Implementation:

javascript
function __es5_indexOf(arr, searchElement, fromIndex) {
    var len = arr.length >>> 0;
    var k = fromIndex ? (fromIndex | 0) : 0;
    if (k >= len) return -1;
    k = Math.max(k >= 0 ? k : len - Math.abs(k), 0);
    while (k < len) {
        if (k in arr && arr[k] === searchElement) return k;
        k++;
    }
    return -1;
}
lastIndexOf(searchElement, fromIndex?) - Returns last index of element

Returns the last index at which an element can be found.

TypeScript:

typescript
const numbers = [1, 2, 3, 2, 1];
const index = numbers.lastIndexOf(2);
// Result: 3

Transforms to:

javascript
__es5_lastIndexOf(numbers, 2)

Implementation:

javascript
function __es5_lastIndexOf(arr, searchElement, fromIndex) {
    var len = arr.length >>> 0;
    var k = fromIndex !== undefined ? (fromIndex | 0) : len - 1;
    k = k >= 0 ? Math.min(k, len - 1) : len - Math.abs(k);
    while (k >= 0) {
        if (k in arr && arr[k] === searchElement) return k;
        k--;
    }
    return -1;
}
every(callback, thisArg?) - Tests if all elements pass a test

Tests whether all elements pass a test.

TypeScript:

typescript
const numbers = [2, 4, 6, 8];
const allEven = numbers.every(n => n % 2 === 0);
// Result: true

Transforms to:

javascript
__es5_every(numbers, function(n) { return n % 2 === 0; })

Implementation:

javascript
function __es5_every(arr, callback, thisArg) {
    var len = arr.length >>> 0;
    for (var k = 0; k < len; k++) {
        if (k in arr && !callback.call(thisArg, arr[k], k, arr)) {
            return false;
        }
    }
    return true;
}
some(callback, thisArg?) - Tests if at least one element passes a test

Tests whether at least one element passes a test.

TypeScript:

typescript
const numbers = [1, 3, 5, 6];
const hasEven = numbers.some(n => n % 2 === 0);
// Result: true

Transforms to:

javascript
__es5_some(numbers, function(n) { return n % 2 === 0; })

Implementation:

javascript
function __es5_some(arr, callback, thisArg) {
    var len = arr.length >>> 0;
    for (var k = 0; k < len; k++) {
        if (k in arr && callback.call(thisArg, arr[k], k, arr)) {
            return true;
        }
    }
    return false;
}

String Methods

trim() - Removes whitespace from both ends

Removes whitespace from both ends of a string.

TypeScript:

typescript
const text = "  hello world  ";
const trimmed = text.trim();
// Result: "hello world"

Transforms to:

javascript
__es5_trim(text)

Implementation:

javascript
function __es5_trim(str) {
    return str.replace(/^\s+|\s+$/g, '');
}
trimLeft() - Removes whitespace from the beginning

Removes whitespace from the beginning of a string.

TypeScript:

typescript
const text = "  hello world  ";
const trimmed = text.trimLeft();
// Result: "hello world  "

Transforms to:

javascript
__es5_trimLeft(text)

Implementation:

javascript
function __es5_trimLeft(str) {
    return str.replace(/^\s+/, '');
}
trimRight() - Removes whitespace from the end

Removes whitespace from the end of a string.

TypeScript:

typescript
const text = "  hello world  ";
const trimmed = text.trimRight();
// Result: "  hello world"

Transforms to:

javascript
__es5_trimRight(text)

Implementation:

javascript
function __es5_trimRight(str) {
    return str.replace(/\s+$/, '');
}

Usage Examples

Example 1: Processing Layers

typescript
// Get all visible layers
const comp = app.project.activeItem as CompItem;
const allLayers: Layer[] = [];
for (let i = 1; i <= comp.numLayers; i++) {
  allLayers.push(comp.layer(i));
}

const visibleLayers = allLayers.filter(layer => layer.enabled);

// Apply effect to each visible layer
visibleLayers.forEach(layer => {
  const effect = (layer as AVLayer).effect.addProperty("ADBE Gaussian Blur 2");
  (effect.property("Blurriness") as OneDProperty).setValue(10);
});

Example 2: Finding Layers by Name

typescript
const comp = app.project.activeItem as CompItem;
const layerNames: string[] = [];
for (let i = 1; i <= comp.numLayers; i++) {
  layerNames.push(comp.layer(i).name);
}

const targetName = "Shape Layer 1";
const index = layerNames.indexOf(targetName);

if (index !== -1) {
  alert("Found layer at index: " + (index + 1));
}

Example 3: Calculating Statistics

typescript
const comp = app.project.activeItem as CompItem;
const durations: number[] = [];
for (let i = 1; i <= comp.numLayers; i++) {
  durations.push(comp.layer(i).outPoint - comp.layer(i).inPoint);
}

const totalDuration = durations.reduce((sum, d) => sum + d, 0);
const avgDuration = totalDuration / durations.length;

alert("Average layer duration: " + avgDuration + " seconds");

Example 4: Validating Layer Properties

typescript
const comp = app.project.activeItem as CompItem;
const layers: Layer[] = [];
for (let i = 1; i <= comp.numLayers; i++) {
  layers.push(comp.layer(i));
}

// Check if all layers are within comp bounds
const allInBounds = layers.every(layer => {
  const pos = layer.property("ADBE Transform Group")
    .property("ADBE Position") as Property;
  const value = pos.value as [number, number];
  return value[0] >= 0 && value[0] <= comp.width &&
         value[1] >= 0 && value[1] <= comp.height;
});

if (!allInBounds) {
  alert("Some layers are outside composition bounds!");
}

Important Notes

Only in TypeScript Script Mode

ES5 transforms are only applied in TypeScript Script mode, not in:

  • JavaScript Script mode (assumes you're writing ES3-compatible code)
  • Expression mode (expressions have different constraints)

Automatic Transformation

You don't need to do anything special:

  1. Write TypeScript code using ES5 methods
  2. Click "Run Script"
  3. expressCode automatically transforms and prepends helpers
  4. The script runs in After Effects

Performance Considerations

The helper functions are optimized implementations that closely match ES5 specifications. However, for very large arrays (1000+ elements), consider:

  • Using traditional for loops for maximum performance
  • Breaking operations into smaller chunks
  • Caching results when possible

Compatibility

These transforms work in all versions of After Effects that support ExtendScript (CS3 and later). The generated code is pure ES3 and doesn't require any modern JavaScript features.

See Also

expressCode v1.0.0 Documentation