SuiteScript 2.1 Language Examples

SuiteScript 2.1 supports ES.Next, which includes the latest published edition of the ECMAScript specification (SuiteScript 2.0 supports ES5.1 only). New editions include many improvements to previous editions of ECMAScript, as well as new language features. For example, ES.Next includes support for constants, block-scoped variables and functions, customizable iterator behavior, typed arrays, and more. You can take advantage of these features when you write SuiteScript 2.1 scripts. You can also consider converting your existing SuiteScript 2.0 scripts to SuiteScript 2.1, since some of these new features may help you improve performance or refactor your code.

In future releases, SuiteScript will continue to support the latest published edition of ECMAScript using ES.Next. ES.Next does not represent a published edition of the ECMAScript specification. Instead, ES.Next refers to future editions of ECMAScript that have not been released yet. ES.Next includes proposed features that have not been approved for inclusion in an official edition. When one of these features is approved, it will be included in the next published edition of the ECMAScript specification. SuiteScript will support all future published editions of ECMAScript. Future minor versions of SuiteScript will also be backward compatible with previous versions

The following sections include examples of using ES.Next features in SuiteScript 2.1:

For more information about new language features, see JavaScript language resources.

Spread Operator

You can use the spread operator to spread the values from two Objects into a new Object:

            const createDynamicRecord = (options) => {
    const defaultOptions = {
        isDynamic: true
    };

    // Spread values from two Objects into a new Object, and create a new record
    return record.create({
        ...defaultOptions,
        ...options
    });
}

const cashSale = createDynamicRecord({
    type: record.Type.CASH_SALE,
    defaultValues: {
        'subsidiary' : '1'
    }
}); 

          

In this example, an arrow function called createDynamicRecord() is created. This function uses a set of default parameter values (represented by defaultOptions) that apply to all records created using this function. When this function is called, additional parameter values can be specified, and these additional values are merged with the default parameter values when record.create(options) is called.

Classes

Note:

If your script contains SuiteScript 2.1 syntax that includes classes and will be included in a bundle, the @NModuleScope JSDoc tag must be set to SameAccount or TargetAccount.

You can create classes to represent common structures:

            /**
 * @NApiVersion 2.1
 */
define(['N/currency', 'N/query'],
    (currency, query) => {
        // Define a class called Transaction
        class Transaction {
            constructor(amount, currency, date, id) {
                this.amount = amount;
                this.currency = currency;
                this.date = date;
                this.id = id;
            }

            // Create a helper function to check if the transaction exists
            exists() {
                return this.id && query.create({
                    type: query.Type.TRANSACTION,
                    condition: query.createCondition({
                        fieldId: 'id',
                        operator: query.Operator.IS,
                        values: this.id
                    })
                 }).run().results.length > 0;
            }

            // Create a helper function to convert transaction amount to a desired currency
            toCurrency(targetCurrency) {
                return this.amount * currency.exchangeRate({
                    date: this.date,
                    source: this.currency,
                    target: targetCurrency
                });
            }
        }

        // Define Sale and Purchase classes that inherits helper methods from the Transaction class
        class Sale extends Transaction {
            constructor(amount, currency, date, customer, id) {
                super(amount, currency, date, id)
                this.customer = customer;
            }
        }
 
        class Purchase extends Transaction {
            constructor(amount, currency, date, vendor, id) {
                super(amount, currency, date, id)
                this.vendor = vendor;
            }
        }

        // Use case: A user attempts to create a Sale or Purchase object from a search or query
        // result set. The user can use the createSale() and createPurchase() functions
        // to create the desired objects.
        return {
            createSale(amount, currency, date, customer, id) {
                return new Sale(amount, currency, date, customer, id);
            },
            createPurchase(amount, currency, date, vendor, id) {
                return new Purchase(amount, currency, date, vendor, id);
            }
        }
    }
); 

          

Destructuring

You can use destructuring to bind variables to different properties of an Object:

            const name = 'data.csv';
const isOnline = true;
const fileType = file.Type.CSV;
const contents = "Alpha,Bravo,Charlie,Delta";

// Create a file using destructured properties
const dataFile = file.create({name, fileType, isOnline, contents}); 

          

Rest Operator

You can use destructured assignment to obtain a single property from an Object, and you can use the rest operator to create a new Object with the remaining properties:

            const {fileType, ...fileProps} = file.load({
    id: 1234
});
log.debug("fileType", fileType);
log.debug("isOnline?", fileProps.isOnline); 

          

Asynchronous Server-Side Promises

SuiteScript 2.1 fully supports non-blocking asynchronous server-side promises expressed using the asnyc, await, and promise keywords for a subset of modules: N/http, N/https, N/query, N/search, and N/transaction. See the help topic Promise Object for a list of promise methods supported in server scripts.

When using server-side promises in SuiteScript, you should consider the following:

  • This capability is not for bulk processing use cases where an out-of-band solution, such as a work queue, may suffice.

  • This capability is mainly for in-process and distinct operations, such as business functions on a list of transactions when ordering does not matter.

The following code sample shows the use of the async and await keywords:

            async function() {
    let myQuery = query.load ({
        id: myQueryId
    });
    let myResult = await myQuery.run().then (function(result) {
        // do stuff
    });
} 

          

For more information about JavaScript promises, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise.

For more information about asynchronous JavaScript programming, see https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous.

For more information about the Promise object in SuiteScript, see Promise Object.

Additional ECMAScript Features

You can also take advantage of the following ECMAScript features when writing SuiteScript 2.1 code:

  • Array.prototype.flat([depth=1])

    • Recursively flattens nested arrays into a single array, up to a given depth

    • Can be used to filter out empty arrays

  • Array.prototype.flat([depth]) …

    Flattens nested arrays returned from sub-tasks

  • Array.prototype.flatMap(callbackFn[, thisArg])

    • Equivalent to first calling map(callbackFn) on an array then flattening (one level deep)

    • Superior performance

  • Object.fromEntries(iterable)

    • Constructs an object from an iterable of key-value pairs

    • A reverse operation to Object.entries(obj)

    • While Object.entries does not emit key-value pairs for Symbol keys, Object.fromEntries fully supports Symbols

  • Promise.any(promises) - fulfilled

    • Takes an iterable of Promises

    • Returns a Promise that is fulfilled as soon as the first promise in the iterable is fulfilled, with the value of that first fulfilled promise

  • Promise.any(promises) and AggregateError - rejected

    • When all Promises in the iterable reject, the returned Promise is also rejected

    • AggregateError is a new Error sub-type; it has a property called errors that holds an array of inner errors

    • The inner errors may or may not be Error instances

  • Promise.allSettled(promises)

    • Returns a Promise that resolves when all input promises are settled

    • Resolved value is an array of result objects corresponding to the input promises

    • By comparison, Promise.all rejects based on the first observed rejection among the input promises

  • Nullish coalescing operator

    • Returns a right-hand side operand if the left-hand side operand is null or undefined (nullish); otherwise returns left-hand side

    • Short-circuits

    • Makes your code shorter and easier to read

    • Proper replacement for the bug-prone use of || (logical OR operator)

  • Optional chaining

    • Similar to “.” operator except that it short-circuits to undefined if the left-hand side is nullish, protecting you from null reference errors

    • Makes your code shorter and easier to read

  • Logical assignment operators - &&=, ||=, ??=

    • Combine condition and assignment into a single operation

    • Short-circuits

      a ( a = b ) becomes a = b

  • Miscellaneous

    • String.prototype.trimStart

    • String.prototype.trimEnd

    • BigInt

    • String.prototype.matchAll

    • String.prototype.replaceAll

    • WeakRef

    • Underscore separators in numerical literals

Related Topics

General Notices