Skip to content

btonasse/suitescript-types

 
 

Repository files navigation

SuiteScript 2.1 Typings

This is a fork of the awesome @hitc/netsuite-types. The main purpose of this library is to provide typing support for vanilla JS development alongside the Typescript support of the original library.

In other words, you can either use Typescript, or keep writing vanilla JS and enjoy full Intellisense/autocompletion on:

  • The imported module instance objects (as long as they're valid N/ modules)
  • The entry point context objects
  • Global modules like N/log and N/util

Installation Instructions

npm install --save-dev @btonasse/suitescript-types

Once installed, create a file called tsconfig.json (for Typescript projects) or jsconfig.json (for vanilla JS):

jsconfig.json:

{
    "compilerOptions": {
        "lib": ["es2022", "DOM"],
        "allowJs": true,
        "checkJs": true,
        "noEmit": true,
        "strict": true,
        "target": "ES2022",
        "skipLibCheck": true,
        "moduleResolution": "node",
        "paths": {
            "N/*": ["./node_modules/@btonasse/suitescript-types/types/N/*"]
        }
    },
    "files": [
        "./node_modules/@btonasse/suitescript-types/types/index.d.ts",
        "./node_modules/@btonasse/suitescript-types/types/SuiteScriptV1.d.ts"
    ],
    "include": ["./**/*"],
    "exclude": ["node_modules"]
}

tsconfig.json:

{
    "compilerOptions": {
        "module": "amd",
        "lib": ["es2022", "DOM"],
        "allowJs": true,
        "checkJs": true,
        "strict": true,
        "target": "ES2022",
        "skipLibCheck": true,
        "moduleResolution": "node",
        "paths": {
            "N/*": ["./node_modules/@btonasse/suitescript-types/types/N/*"]
        }
    },
    "files": [
        "./node_modules/@btonasse/suitescript-types/types/index.d.ts",
        "./node_modules/@btonasse/suitescript-types/types/SuiteScriptV1.d.ts"
    ],
    "include": ["./**/*.ts"],
    "exclude": ["node_modules"]
}

Usage

Callback function and entry points

To get Intellisense/autocompletion in JS files, you can structure your callback function in two different ways:

/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(["N/record", "N/search"], (record, search) => {
    return {
        beforeLoad: (scriptContext) => {
            // entry point implementation
        },
        beforeSubmit: (scriptContext) => {
            // entry point implementation
        },
    };
});

Or

/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(["N/record", "N/search"], (record, search) => {
    /** @type {import("N/entryPoints").UserEvent.beforeLoad} */
    const beforeLoad = (scriptContext) => {
        // entry point implementation
    };
    /** @type {import("N/entryPoints").UserEvent.beforeSubmit} */
    const beforeSubmit = (scriptContext) => {
        // entry point implementation
    };

    return {
        beforeLoad: beforeLoad,
        beforeSubmit: beforeSubmit,
    };
});

JSDoc types

Usually your IDE will pick-up the correct type in a JSDoc annotation. However, for certain interfaces like Record and Sublist, there can be conflicts with either built-in interfaces or other N modules. For example:

/**
 * @param {Record} currentRecord
 */
const myFunc = (currentRecord) => {
    // What is the type of currentRecord?
};

In the example above the IDE might not infer the type correctly (are we're referring to N/record, N/workbook or even the typescript built-in with the same name?). To solve this, use import types as per the official TypeScript documentation

/**
 * @param {import("N/record").Record} currentRecord
 */
const myFunc = (currentRecord) => {
    // Now we know we're talking about N/record!
};

Custom Modules

To enforce type safety, all custom modules imported with relative paths are typed by default as Record<string, unknown>. This means you need to provide the types to the imported module yourself. For example:

A custom module defined in ./myModule.js:

/**
 * @NApiVersion 2.1
 */
define([], () => {
    return {
        myFunc: () => {
            return true;
        },
    };
});

Consumer script:

/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(["N/record", "./myModule"], (record, lib) => {
    return {
        beforeLoad: (ctx) => {
            // TS will flag an error. The type of lib.myFunc is unknown
            const isTrue = lib.myFunc();
        },
    };
});

There are two ways to achieve this:

  1. With JSDoc annotations:
/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(["N/record", "./myModule"], (record, _lib) => {
    const lib = /**@type{{myFunc: () => boolean}}*/ (_lib);
    return {
        beforeLoad: (ctx) => {
            // TS now knows that lib.myFunc returns a boolean
            const isTrue = lib.myFunc();
        },
    };
});
  1. Augmenting the global ModuleMap interface (a mapping of all supported SuiteScript modules defined by this library) within a .d.ts file:
// ./myModule.d.ts
interface ModuleMap {
    "./myModule": {
        myFunc: () => boolean;
    };
}
/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(["N/record", "./myModule"], (record, lib) => {
    return {
        beforeLoad: (ctx) => {
            // TS still knows that lib.myFunc returns a boolean
            const isTrue = lib.myFunc();
        },
    };
});

About

TypeScript typings for SuiteScript 2.1

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 100.0%