Appearance
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:
- Transforming modern method calls into helper function calls
- 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: 10Transforms 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: 10Transforms 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: 1Transforms 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: 3Transforms 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: trueTransforms 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: trueTransforms 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:
- Write TypeScript code using ES5 methods
- Click "Run Script"
- expressCode automatically transforms and prepends helpers
- 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
- TypeScript Reference - Full TypeScript support details
- User Guide - Complete guide to using expressCode
- MDN Web Docs - Full ES5 method documentation