SOL FINAL - Attachment 9 - USPTO JavaScript Coding Standard.pdf

PDF 1 MB Posted

Attached to
USPTO Enterprise Cloud Modernization (ECM)
Solicitation number
1333BJ26R00280002
Issued by

About this file

This is a coding standards document for JavaScript and TypeScript development at the United States Patent and Trademark Office. The document, designated OCIO-STD-010 Version 4.0 (effective September 15, 2025), establishes mandatory coding standards for all JavaScript/TypeScript code delivered by USPTO or contractor staff. The standard is based on the Google JavaScript Style Guide and Google TypeScript Style Guide under CC BY 3.0 licensing, with Version 4.0 incorporating new TypeScript coding standards. The Office of the Chief Information Officer (OCIO), Office of Business Product Delivery Office (BPDO) serves as the office of primary interest, with the Developer Experience Branch handling questions and comments.

The standard covers comprehensive requirements across ten major sections: source file basics (UTF-8 encoding requirements), source file structure (copyright information, JSDoc organization, ES6 module imports/exports), formatting (brace style, indentation using spaces, 120-character column limit, line-wrapping rules), language features (variable declarations using const and let, array and object literals, class and function declarations), naming conventions (camelCase for identifiers), TypeScript-specific type system rules, toolchain requirements, and comments and documentation standards using JSDoc. Key requirements include mandatory semicolons, K&R style braces, use of named exports over default exports, preference for const declarations, avoidance of the Array constructor, use of arrow functions for callbacks, and structural typing for interfaces. The standard prohibits CommonJS in new code (favoring ES6 modules), namespace declarations, mutable exports, var declarations, and numerous other patterns deemed to reduce code quality or security. The document is Section 508 compliant and intended for USPTO staff and contract developers responsible for JavaScript/TypeScript development.

View the file

Other files

Show all 11

On GovTribe

Work with this file

  • Download the original file
  • Contacts named in this file
  • Similar government files
  • Ask GovTribe AI about this file

Text version

USPTO/OCIO

USPTO JavaScript/TypeScript

Coding Standard

OCIO-STD-010

Version 4.0

September 15, 2025

USPTO JavaScript/TypeScript Coding Standard

Version 4.0 2 of 99 9/15/2025

Record of Changes/Version History

Version Number

Date of Change

Sections Affected

Type of Reason(s) for Changes

Draft 3.0 1/10/2019 All • Removed outdated sections from version 2.0

• Adopted a subset of the Google JavaScript Style

Guide under CC BY 3.0

• It includes a smattering of guidelines from the

WordPress JavaScript Coding Standards

3.0 final 3/20/2019 Routing Sheet

Approval Page Reviewer e-signature pages CIO Final Approval signature

Draft 4.0 9/15/2025 All Incorporated TypeScript coding standard https://google.github.io/styleguide/jsguide.html#introduction https://google.github.io/styleguide/jsguide.html#introduction https://google.github.io/styleguide/jsguide.html#introduction https://creativecommons.org/licenses/by/3.0/ https://make.wordpress.org/core/handbook/best-practices/coding-standards/javascript/ https://make.wordpress.org/core/handbook/best-practices/coding-standards/javascript/ https://make.wordpress.org/core/handbook/best-practices/coding-standards/javascript/

Version 4.0 3 of 99 9/15/2025

1 INTRODUCTION

1.1 PURPOSE

1.2 BENEFITS

1.3 SCOPE

1.4 OFFICE OF PRIMARY INTEREST

1.5 INTENDED AUDIENCE

1.6 RELATIONSHIP TO POLICIES AND OTHER STANDARDS

1.7 DOCUMENT CONVENTIONS

1.7.1 Fixed-Width Font

1.7.2 Sample Code

1.8 SECTION 508 COMPLIANCE

2 SOURCE FILE BASICS

2.1 FILE ENCODING: UTF-8

2.1.1 Whitespace characters

2.1.2 Special escape sequences

2.1.3 Non-ASCII characters

3 SOURCE FILE STRUCTURE

3.1 COPYRIGHT INFORMATION

3.2 @FILEOVERVIEW JSDOC

3.3 IMPORTS

3.3.1 Import Paths

3.3.2 Namespace versus named imports

3.3.3 Renaming imports

3.4 EXPORTS

3.4.1 Mutable exports

3.4.2 Export visibility

3.4.3 Container classes

3.5 IMPORT AND EXPORT TYPE (TYPESCRIPT)

3.5.1 Import type

3.5.2 Export type

3.5.3 Use modules not namespaces

4 FORMATTING

4.1 BRACES

4.1.1 Braces are used for all control structures

4.1.2 Nonempty blocks: K&R style

4.1.3 Empty blocks: may be concise

4.2 BLOCK INDENTATION: USE SPACES

4.2.1 Array literals: optionally block-like

4.2.2 Object literals: optionally block-like

4.2.3 Class literals

4.2.4 Function expressions

4.2.5 Switch statements

4.3 STATEMENTS

4.3.1 One statement per line

4.3.2 Semicolons are required

4.4 COLUMN LIMIT: 120

4.5 LINE-WRAPPING

4.5.1 Where to break

4.5.2 Indent continuation lines at least +2 spaces

Version 4.0 4 of 99 9/15/2025

4.6 WHITESPACE

4.6.1 Vertical whitespace

4.6.2 Horizontal whitespace

4.6.3 Function arguments

4.7 GROUPING PARENTHESES: RECOMMENDED

5 LANGUAGE FEATURES

5.1 LOCAL VARIABLE DECLARATIONS

5.1.1 Use const and let

5.2 ARRAY LITERALS

5.2.1 Do not use the Array constructor

5.2.2 Do not define properties on arrays

5.2.3 Using spread syntax

5.2.4 Array destructuring

5.3 OBJECT LITERALS

5.3.1 Do not use the Object constructor

5.3.2 Do not mix quoted and unquoted keys

5.3.3 Iterating objects

5.3.4 Using spread syntax

5.3.5 Computed property names

5.3.6 Method shorthand

5.3.7 Shorthand properties

5.3.8 Object destructuring

5.3.9 Enums

5.4 CLASSES

5.4.1 Class declarations

5.4.2 Class method declarations

5.4.2.1 Overriding toString

5.4.3 Static methods

5.4.3.1 Avoid private static methods

5.4.3.2 Do not rely on dynamic dispatch

5.4.3.3 Avoid static this references

5.4.4 Constructors

5.4.5 Class members

5.4.5.1 Computed properties

5.4.5.2 No #private fields

5.4.5.3 Field initializers

5.4.5.4 Use readonly (TypeScript)

5.4.5.5 Parameter properties (TypeScript)

5.4.5.6 Properties used outside of class lexical scope (TypeScript)

5.4.5.7 Getters and setters (TypeScript)

5.4.5.8 Getters and setters (JavaScript)

5.4.6 Disallowed class patterns

5.4.6.1 Do not manipulate prototypes directly

5.4.7 Visibility (TypeScript)

5.4.8 Old-style class declarations (Javascript)

5.5 FUNCTIONS

5.5.1 Terminology

5.5.2 Prefer function declarations for named functions

5.5.3 Nested functions

5.5.4 Do not use function expressions

5.5.5 Arrow function bodies

5.5.6 Rebinding this

5.5.7 Prefer passing arrow functions as callbacks

Version 4.0 5 of 99 9/15/2025

5.5.8 Arrow functions as properties

5.5.9 Event handlers

5.5.10 Parameter initializers

5.5.11 Prefer rest and spread when appropriate

5.5.12 Formatting functions

5.6 THIS

5.7 PRIMITIVE LITERALS

5.7.1 String literals

5.7.1.1 Use single quotes

5.7.1.2 No line continuations

5.7.1.3 Template literals

5.7.2 Number literals

5.7.3 Type coercion (TypeScript)

5.7.3.1 Implicit coercion

5.8 CONTROL STRUCTURES

5.8.1 Control flow statements and blocks

5.8.1.1 Assignment in control statements

5.8.1.2 Iterating containers

5.8.2 Grouping parentheses

5.8.3 Exception handling

5.8.3.1 Instantiate errors using new

5.8.3.2 Only throw errors

5.8.3.3 Catching and rethrowing

5.8.3.4 Empty catch blocks

5.8.4 Switch statements

5.8.5 Equality checks

5.8.6 Keep try blocks focused

5.8.7 Type and non-nullability assertions (TypeScript)

5.8.7.1 Type assertion syntax

5.8.7.2 Double assertions

5.8.7.3 Type assertions and object literals

5.9 DISALLOWED FEATURES

5.9.1 Wrapper objects for primitive types

5.9.2 Automatic Semicolon Insertion

5.9.3 Debugger statements

5.9.4 With

5.9.5 Dynamic code evaluation

5.9.6 Non-standard features

5.9.7 Modifying built-in objects

5.9.8 Other disallowed features

5.9.9 Const enums (TypeScript)

5.10 DECORATORS (TYPESCRIPT)

6 NAMING

6.1 IDENTIFIERS

6.1.1 Naming style

6.1.2 Descriptive names

6.1.3 Camel case

6.1.4 Dollar sign

6.2 RULES BY IDENTIFIER TYPE

6.2.1 Test names

6.2.2 prefix/suffix

6.2.3 Imports

6.2.4 Constants

Version 4.0 6 of 99 9/15/2025

6.2.5 Aliases

6.2.6 Type parameters (TypeScript)

7 TYPE SYSTEM (TYPESCRIPT)

7.1 TYPE INFERENCE

7.1.1 Return types

7.2 UNDEFINED AND NULL

7.2.1 Nullable/undefined type aliases

7.2.2 Prefer optional over |undefined

7.3 USE STRUCTURAL TYPES

7.4 PREFER INTERFACES OVER TYPE LITERAL ALIASES

7.5 ARRAY<T> TYPE

7.6 INDEXABLE TYPES / INDEX SIGNATURES ({[KEY: STRING]: T})

7.7 MAPPED AND CONDITIONAL TYPES

7.8 ANY TYPE

7.8.1 Providing a more specific type

7.8.2 Using unknown over any

7.9 {} TYPE

7.10 TUPLE TYPES

7.11 WRAPPER TYPES

7.12 RETURN TYPE ONLY GENERICS

8 TOOLCHAIN REQUIREMENTS (TYPESCRIPT)

8.1 TYPESCRIPT COMPILER

8.1.1 @ts-ignore

9 COMMENTS AND DOCUMENTATION

9.0.1 JSDoc versus comments

9.0.2 Multi-line comments

9.1 JSDOC GENERAL FORM

9.2 MARKDOWN

9.3 JSDOC TAGS

9.4 LINE WRAPPING

9.5 DOCUMENT ALL TOP-LEVEL EXPORTS OF MODULES

9.6 CLASS COMMENTS

9.7 METHOD AND FUNCTION COMMENTS

9.8 PARAMETER PROPERTY COMMENTS

9.9 JSDOC TYPE ANNOTATIONS

9.10 MAKE COMMENTS THAT ACTUALLY ADD INFORMATION

9.10.1 Comments when calling a function

9.11 PLACE DOCUMENTATION PRIOR TO DECORATORS

10 REFERENCES

11 APPROVAL SIGNATURE

Version 4.0 7 of 99 9/15/2025

1 Introduction

1.1 Purpose

This document specifies the JavaScript/TypeScript Coding Standard enforced by the United States Patent and Trademark Office. The standard established by this document pertains to the JavaScript/TypeScript Programming Language in lieu of its sibling technologies of HTML and CSS. This standard is not comprehensive and is subject to change over time. Nevertheless, it provides a strong starting point for developing readable and secure code.

1.2 Benefits

Coding standards and guidelines are beneficial for ensuring code quality. Quality code has these fundamental characteristics:

1. Readable/Concise – code is readily understood by other developers by virtue of its clarity and adherence to expected formatting and naming conventions. The logic is largely self-documenting with sporadic comments used to explain less obvious segments of code.

Methods and non-local variables have explanatory comments. Each method has an ideally singular purpose.

2. Correct/Consistent – code works as intended in all reasonable circumstances, including multiple browser environments and preferably under greater-than- normal application demands (e.g. user loads, network delays, etc.).

3. Secure – code is not susceptible to problems that would compromise sensitive data or result in prolonged application failure.

1.3 Scope

Compliance with this standard is required of code delivered for any development project using JavaScript/Typescript, whether produced by USPTO or contractor staff.

1.4 Office of Primary Interest

The USPTO, Office of the Chief Information Officer (OCIO), Office of Business Product Delivery Office (BPDO) is the office of primary interest for this document. Any questions or comments about the content of this document should be addressed to BPDO’s Developer Experience Branch.

Version 4.0 8 of 99 9/15/2025

1.5 Intended Audience

The intended audience for this document is USPTO staff and contract developers who are responsible for JavaScript/TypeScript development.

1.6 Relationship to Policies and Other Standards

This document is the fourth version of the JavaScript/TypeScript standard for the USPTO. It is based on the Google JavaScript Style Guide/Google TypeScript Style Guide under CC BY 3.0.

All additions and changes are noted above in the “Version History” section.

1.7 Document Conventions

1.7.1 Fixed-Width Font

JavaScript/TypeScript keywords, package and class names, and other inline code fragments appear in a fixed-width font to aid in readability.

1.7.2 Sample Code

Sample code appears within text boxes using a fixed-width font. Code is syntax highlighted for easier readability. Sample code is shown within text boxes containing both conformant and non-conformant code; these use a black border but have inline comments like //AVOID to indicate which particular lines do not conform. The conforming code has inline comments like

//PREFERRED.

Some sample code may take liberties with prescribed naming and/or formatting conventions, especially in regards to blank lines and line length, in order to display appropriately within this document.

1.8 Section 508 Compliance

The document has been through the section 508 compliance validation and evaluation. It contains no Section 508 compliance issues.

2 Source file basics

2.1 File encoding: UTF-8

Source files are encoded in UTF-8.

https://google.github.io/styleguide/jsguide.html https://google.github.io/styleguide/tsguide.html https://creativecommons.org/licenses/by/3.0/

Version 4.0 9 of 99 9/15/2025

2.1.1 Whitespace characters

Aside from the line terminator sequence, the ASCII horizontal space character (0x20) is the only whitespace character that appears anywhere in a source file. This implies that all other whitespace characters in string literals are escaped.

2.1.2 Special escape sequences

For any character that has a special escape sequence (\', \", \\, \b, \f, \n, \r, \t, \v), that sequence is used rather than the corresponding numeric escape (e.g. \x0a, \u000a, or \u{a}).

Legacy octal escapes are never used.

2.1.3 Non-ASCII characters

For the remaining non-ASCII characters, use the actual Unicode character (e.g. ∞). For non-printable characters, the equivalent hex or Unicode escapes (e.g. \u221e) can be used along with an explanatory comment.

Non-ASCII characters

// PREFERRED

// Perfectly clear, even without a comment.

const units = 'μs';

// Use escapes for non-printable characters.

const output = '\ufeff' + content; // byte order mark

// AVOID

// Hard to read and prone to mistakes, even with the comment.

const units = '\u03bcs'; // Greek letter mu, 's'

// The reader has no idea what this is.

const output = '\ufeff' + content;

3 Source file structure

Version 4.0 10 of 99 9/15/2025

Files consist of the following, in order:

1. Copyright information, if present

2. JSDoc with @fileoverview, if present

3. Imports, if present

4. The file’s implementation

Exactly one blank line separates each section that is present.

3.1 Copyright information

If license or copyright information is necessary in a file, add it in a JSDoc at the top of the file.

If the work contains source code from open source and the open-source code is used as-is, the licensure and copyright information of the open-source code shall be included for that open-source code. If the work contains source code from open source and the open-source code has been modified, then the licensure and copyright of the open-source code must be complied with and shall be included for that modified open-source code, including any requirement to annotate codes changes. In cases where the licensure requires the sharing of any code changes or modifications to the open-source component(s), the government shall be notified of the intent to use and specific permission to use and contribute those changes must be given before the code may be used.

3.2 @fileoverview JSDoc

A file may have a top-level @fileoverview JSDoc. If present, it may provide a description of the file's content, its uses, or information about its dependencies. Wrapped lines are not indented.

@fileoverview JS Doc

* @fileoverview Description of file. Lorem ipsum dolor sit amet, consectetur

* adipiscing elit, sed do eiusmod tempor incididunt.

3.3 Imports

This standard assumes and prefers ES module (ESM) syntax (import / export) for new code.

While ESModule is the recommended and supported module format, we recognize that some existing packages and build/runtime environments still require CommonJS ( require / module.exports ). CommonJS use is not recommended for new code. If you must use or consume CommonJS packages, clearly document that in the module’s README and prefer to wrap or isolate CommonJS interop at the project boundary so most application code remains ESM.

Version 4.0 11 of 99 9/15/2025

There are four variants of import statements in ES6 and TypeScript:

Import type Example Use for module[module_import] import * as foo from ...'; TypeScript Imports named[destructuring_import] import { SomeThing } from '...'; TypeScript Imports default import SomeThing from '...';

Only for other external code that requires them side-effect import '...';

Only to import libraries for their side-effects on load (such as custom elements)

Imports

// Good: choose between two options as appropriate (see below).

import * as ng from '@angular/core';

import { Foo } from './foo';

// Only when needed: default imports.

import Button from 'Button';

// Sometimes needed to import libraries for their side effects:

import 'jasmine';

import '@polymer/paper-button';

3.3.1 Import Paths

TypeScript code must use paths to import other TypeScript code. Paths may be relative, i.e.

starting with . or .. or rooted at the base directory, e.g. root/path/to/file.

Code should use relative imports (. /foo) rather than absolute imports path/to/foo when referring to files within the same (logical) project as this allows to move the project around without introducing changes in these imports.

Consider limiting the number of parent steps (./../../) as those can make module and path structures hard to understand.

Version 4.0 12 of 99 9/15/2025

Import Paths

// PREFERRED

import { Symbol1 } from 'path/from/root';

import { Symbol2 } from '../parent/file';

import { Symbol3 } from './sibling';

3.3.2 Namespace versus named imports

Both namespace and named imports can be used.

Prefer named imports for symbols used frequently in a file or for symbols that have clear names, for example Jasmine's describe and it. Named imports can be aliased to clearer names as needed with as.

Prefer namespace imports when using many different symbols from large APIs. A namespace import, despite using the * character, is not comparable to a wildcard import as seen in other languages. Instead, namespace imports give a name to all the exports of a module, and each exported symbol from the module becomes a property on the module name. Namespace imports can aid readability for exported symbols that have common names like Model or Controller without the need to declare aliases.

// Bad: overlong import statement of needlessly namespaced names.

import {Item as TableviewItem, Header as TableviewHeader, Row as TableviewRow, Model as TableviewModel, Renderer as TableviewRenderer} from './tableview';

let item: TableviewItem|undefined;

// PREFERRED

// Better: use the module for namespacing.

import * as tableview from './tableview';

let item: tableview.Item|undefined;

// AVOID

import * as testing from './testing';

// Bad: The module name does not improve readability.

Version 4.0 13 of 99 9/15/2025 testing.describe('foo', () => { testing.it('bar', () => { testing.expect(null).toBeNull();

testing.expect(undefined).toBeUndefined();

// PREFERRED

// Better: give local names for these common functions.

import { describe, it, expect } from './testing';

describe('foo', () => { it('bar', () => { expect(null).toBeNull();

expect(undefined).toBeUndefined();

Special case: Apps JSPB protos

Apps JSPB protos must use named imports, even when it leads to long import lines.

This rule exists to aid in build performance and dead code elimination since often .proto files contain many messages that are not all needed together. By leveraging destructured imports the build system can create finer grained dependencies on Apps JSPB messages while preserving the ergonomics of path-based imports.

JSPB Import

// Good: import the exact set of symbols you need from the proto file.

import { Foo, Bar } from './foo.proto';

function copyFooBar(foo: Foo, bar: Bar) {...}

3.3.3 Renaming imports

Code should fix name collisions by using a namespace import or renaming the exports themselves. Code may rename imports (import { SomeThing as SomeOtherThing }) if needed.

Three examples where renaming can be helpful:

• If it's necessary to avoid collisions with other imported symbols.

Version 4.0 14 of 99 9/15/2025

• If the imported symbol name is generated.

• If importing symbols whose names are unclear by themselves, renaming can improve code clarity. For example, when using RxJS the from function might be more readable when renamed to observableFrom.

3.4 Exports

Use named exports in all code:

Exports

// PREFERRED

// Use named exports:

export class Foo { ... }

// AVOID

// Do not use default exports:

export default class Foo { ... } // Bad!

Why?

// AVOID

// Default exports provide no canonical name, which makes central maintenance difficult with relatively little benefit to code owners, including potentially decreased readability:

import Foo from './bar'; // Legal.

import Bar from './bar'; // Also legal.

// Named exports have the benefit of erroring when import statements try to import something that hasn't been declared. In foo.ts:

const foo = 'blah';

export default foo;

// And in bar.ts

Version 4.0 15 of 99 9/15/2025 import {fizz} from './foo';

// Results in error TS2614: Module '"./foo"' has no exported member 'fizz'. While bar.ts:

import fizz from './foo';

// Results in fizz === foo, which is probably unexpected and difficult to debug.

// Additionally, default exports encourage people to put everything into one big object to namespace it all together:

export default class Foo { static SOME_CONSTANT = ...

static someHelpfulFunction() { ... }

With the above pattern, we have file scope, which can be used as a namespace. We also have a perhaps needless second scope (the class Foo) that can be ambiguously used as both a type and a value in other files.

Instead, prefer use of file scope for namespacing, as well as named exports:

export const SOME_CONSTANT = ...

export function someHelpfulFunction() export class Foo { // only class stuff here

3.4.1 Mutable exports

Regardless of technical support, mutable exports can create hard to understand and debug code, in particular with re-exports across multiple modules. One way to paraphrase this style point is that export let is not allowed.

Mutable exports export let foo = 3;

// In pure ES6, foo is mutable and importers will observe the value change after a second.

// In TS, if foo is re-exported by a second file, importers will not see the value change.

Version 4.0 16 of 99 9/15/2025 window.setTimeout(() => { foo = 4;

}, 1000 /* ms */);

If one needs to support externally accessible and mutable bindings, they should instead use explicit getter functions.

let foo = 3;

window.setTimeout(() => { foo = 4;

}, 1000 /* ms */);

// Use an explicit getter to access the mutable export.

export function getFoo() { return foo; };

For the common pattern of conditionally exporting either of two values, first do the conditional check, then the export. Make sure that all exports are final after the module's body has executed.

Mutable exports

// PREFERRED

function pickApi() { if (useOtherApi()) return OtherApi;

return RegularApi;

export const SomeApi = pickApi();

3.4.2 Export visibility

TypeScript/JavaScript does not support restricting the visibility for exported symbols. Only export symbols that are used outside of the module. Generally minimize the exported API surface of modules.

3.4.3 Container classes

Do not create container classes with static methods or properties for the sake of namespacing.

Instead, export individual constants and functions:

Version 4.0 17 of 99 9/15/2025

Container class

// AVOID

export class Container { static FOO = 1;

static bar() { return 1; }

// PREFERRED

// export individual constants and functions:

export const FOO = 1;

export function bar() { return 1; }

3.5 Import and export type (TypeScript)

3.5.1 Import type

You may use import type {...} when you use the imported symbol only as a type. Use regular imports for values:

Import type import type { Foo } from './foo';

import { Bar } from './foo';

import { type Foo, Bar } from './foo';

The TypeScript compiler automatically handles the distinction and does not insert runtime loads for type references. So why annotate type imports?

The TypeScript compiler can run in 2 modes:

• In development mode, we typically want quick iteration loops. The compiler transpiles to JavaScript without full type information. This is much faster, but requires import type in certain cases.

• In production mode, we want correctness. The compiler type checks everything and ensures import type is used correctly.

Note: If you need to force a runtime load for side effects, use import '...';.

3.5.2 Export type

Version 4.0 18 of 99 9/15/2025

Use export type when re-exporting a type, e.g.:

Export type export type { AnInterface } from './foo';

export type is useful to allow type re-exports in file-by-file transpilation.

export type might also seem useful to avoid ever exporting a value symbol for an API. However it does not give guarantees, either: downstream code might still import an API through a different path. A better way to split & guarantee type vs value usages of an API is to actually split the symbols into e.g. UserService and AjaxUserService. This is less error prone and also better communicates intent.

3.5.3 Use modules not namespaces

TypeScript supports two methods to organize code: namespaces and modules, but namespaces are disallowed. That is, your code must refer to code in other files using imports and exports of the form import { foo } from 'bar';

Your code must not use the namespace Foo { ... } construct. namespaces may only be used when required to interface with external, third party code. To semantically namespace your code, use separate files.

Code must not use require (as in import x = require('...');) for imports. Use ES6 module syntax.

Use modules not namespaces

// Bad: do not use namespaces:

namespace Rocket { function launch() { ... }

// Bad: do not use <reference> /// <reference path="..."/>

// Bad: do not use require() import x = require('mydep');

Version 4.0 19 of 99 9/15/2025

Note: TypeScript namespaces used to be called internal modules and used to use the module keyword in the form module Foo { ... }. Don't use that either. Always use ES6 imports.

4 Formatting

Tip: Consider using clang-format or ESLint to check formatting The JavaScript community has invested effort to make sure clang-format does the right thing on JavaScript files. clang-format has integration with several popular editors.

4.1 Braces

4.1.1 Braces are used for all control structures

Braces are required for all control structures (i.e. if, else, for, do, while, as well as any others), even if the body contains only a single statement. The first statement of a non- empty block must begin on its own line.

Braces are used for all control structures if (someVeryLongCondition()) doSomething();

for (let i = 0; i < foo.length; i++) bar(foo[i]);

Exception: A simple if statement that can fit entirely on a single line with no wrapping (and that doesn’t have an else) may be kept on a single line with no braces when it improves readability.

This is the only case in which a control structure may omit braces and newlines.

Braces are used for all control structures

// EXCEPTION

if (shortCondition()) return;

4.1.2 Nonempty blocks: K&R style

Braces follow the Kernighan and Ritchie style (Egyptian brackets) for nonempty blocks and block-like constructs:

• No line break before the opening brace.

• Line break after the opening brace.

• Line break before the closing brace.

Version 4.0 20 of 99 9/15/2025

• Line break after the closing brace if that brace terminates a statement or the body of a function or class statement, or a class method. Specifically, there is no line break after the brace if it is followed by else, catch, while, or a comma, semicolon, or right-parenthesis.

Nonempty blocks: K&R style

// EXAMPLE

class InnerClass { constructor() {} method(foo) { if (condition(foo)) { try {

// Note: this might fail.

something();

catch (err) { recover();

4.1.3 Empty blocks: may be concise

An empty block or block-like construct may be closed immediately after it is opened, with no characters, space, or line break in between (i.e. {}), unless it is a part of a multi- block statement (one that directly contains multiple blocks: if/else or try/catch/finally). The empty block for a multi-block statement must contain a comment.

Version 4.0 21 of 99 9/15/2025

Empty blocks: may be concise

// EXAMPLE

function doNothing() {} try {

} catch (e) { // catch me

// AVOID

if (condition) {

} else if (otherCondition) {} else { try {

} catch (e) {}

4.2 Block indentation: use spaces

Each time a new block or block-like construct is opened, the indent increases by at least +2 spaces. Use the indentation spacing consistently. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block.

(See the example in Section 4.1.2).

4.2.1 Array literals: optionally block-like

Any array literal may optionally be formatted as if it were a “block-like construct.” For example, the following are all valid (not an exhaustive list):

Version 4.0 22 of 99 9/15/2025

Array literals: optionally block-like

// EXAMPLE

const a = [ 0, 1, 2, const b = [0, 1, 2];

const c = [0, 1, 2];

someMethod(foo, [ 0, 1, 2, ], bar);

Other combinations are allowed, particularly when emphasizing semantic groupings between elements, but should not be used only to reduce the vertical size of larger arrays.

4.2.2 Object literals: optionally block-like

Any object literal may optionally be formatted as if it were a “block-like construct.” The same examples apply as in Section 4.2.1. For example, the following are all valid (not an exhaustive list):

Object literals: optionally block-like const a = { a: 0, b: 1, const b = {a: 0, b: 1};

const c = {a: 0, b: 1};

someMethod(foo, { a: 0, b: 1, }, bar);

4.2.3 Class literals

Class literals (whether declarations or expressions) are indented as blocks. Do not add semicolons after methods, or after the closing brace of a class declaration (statements - such as

Version 4.0 23 of 99 9/15/2025 assignments - that contain class expressions are still terminated with a semicolon). For inheritance, the extends keyword is sufficient unless the superclass is templatized.

Class literals class Foo { constructor(x) { this.x = x;

class Bar extends Foo { constructor() { super(42);

exports.Baz = class extends Bar { /** @return {number} */ method() { return this.x;

4.2.4 Function expressions

When declaring an anonymous function in the list of arguments for a function call, the body of the function is indented more than the preceding indentation depth using spaces.

Version 4.0 24 of 99 9/15/2025

Function expressions

// EXAMPLE:

prefix.something.reallyLongFunctionName('whatever', (a1, a2) => {

// Indent the function body relative to indentation depth // of the 'prefix' statement one line above.

if (a1.equals(a2)) { someOtherLongFunctionName(a1);

} else { andNowForSomethingCompletelyDifferent(a2.parrot);

some.reallyLongFunctionCall(arg1, arg2, arg3) .thatsWrapped() .then((result) => { // Indent the function body relative to the indentation depth // of the '.then()' call.

if (result) { result.use();

4.2.5 Switch statements

As with any other block, the contents of a switch block are indented using spaces.

After a switch label, a newline appears, and the indentation level is increased using spaces, exactly as if a block were being opened. An explicit block may be used if required by lexical scoping. The following switch label returns to the previous indentation level, as if a block had been closed.

Use a break for each case other than default. When allowing statements to “fall through,” note that explicitly. A blank line is optional between a break and the following case.

Switch statements

// EXAMPLE:

switch (animal) { case Animal.BANDERSNATCH:

handleBandersnatch();

break;

case Animal.JABBERWOCK:

handleJabberwock();

break;

default:

throw new Error('Unknown animal');

Version 4.0 25 of 99 9/15/2025

Switch statements

4.3 Statements

4.3.1 One statement per line

Each statement is followed by a line-break.

4.3.2 Semicolons are required

Every statement must be terminated with a semicolon. Relying on automatic semicolon insertion is forbidden.

4.4 Column limit: 120

JavaScrip/TypeScript code should usually not exceed a column limit of 120 characters. Except as noted below, any line that would exceed this limit must be line-wrapped, as explained in Section

4.5 Line-wrapping below.

Exceptions:

1. ES module import and export from statements.

2. Lines where obeying the column limit is not possible or would hinder discoverability.

Examples include:

• A long URL which should be clickable in source.

• A shell command intended to be copied-and-pasted.

• A long string literal which may need to be copied or searched for wholly (e.g., a long file path).

4.5 Line-wrapping

Terminology Note: Line-wrapping is defined as breaking a single expression into multiple lines.

There is no comprehensive, deterministic formula showing exactly how to line-wrap in every situation. Very often there are several valid ways to line-wrap the same piece of code.

Note: While the typical reason for line-wrapping is to avoid overflowing the column limit, even code that would in fact fit within the column limit may be line-wrapped at the author's discretion.

Tip: Extracting a method or local variable may solve the problem without the need to line-wrap.

Version 4.0 26 of 99 9/15/2025

4.5.1 Where to break

The prime directive of line-wrapping is: prefer to break at a higher syntactic level.

Where to break

// PREFERRED:

currentEstimate = calc(currentEstimate + x * currentEstimate) /

2.0f;

// AVOID:

currentEstimate = calc(currentEstimate + x * currentEstimate) / 2.0f;

In the preceding example, the syntactic levels from highest to lowest are as follows: assignment, division, function call, parameters, number constant.

Operators are wrapped as follows:

1. When a line is broken at an operator the break comes after the symbol.

a. This does not apply to the dot (.), which is not actually an operator.

2. A method or constructor name stays attached to the open parenthesis (() that follows it.

3. A comma (,) stays attached to the token that precedes it.

Note: The primary goal for line wrapping is to have clear code, not necessarily code that fits in the smallest number of lines.

4.5.2 Indent continuation lines at least +2 spaces

When line-wrapping, each line after the first (each continuation line) is indented at least +2 from the original line, unless it falls under the rules of block indentation.

When there are multiple continuation lines, indentation may be varied beyond +2 as appropriate.

In general, continuation lines at a deeper syntactic level are indented by larger multiples of 2, and two lines use the same indentation level if and only if they begin with syntactically parallel elements.

4.6 Whitespace

4.6.1 Vertical whitespace

Version 4.0 27 of 99 9/15/2025

A single blank line appears:

1. Between consecutive methods in a class or object literal

a. Exception: A blank line between two consecutive properties definitions in an object literal (with no other code between them) is optional. Such blank lines are used as needed to create logical groupings of fields.

2. Within method bodies, sparingly to create logical groupings of statements. Blank lines at the start or end of a function body are not allowed.

3. Optionally before the first or after the last method in a class or object literal (neither encouraged nor discouraged).

4. As required by other sections of this document.

Multiple consecutive blank lines are permitted, but never required (nor encouraged).

4.6.2 Horizontal whitespace

Use of horizontal whitespace depends on location, and falls into three broad categories: leading (at the start of a line), trailing (at the end of a line), and internal. Leading whitespace (i.e., indentation) is addressed elsewhere. Trailing whitespace is forbidden.

Beyond where required by the language or other style rules, and apart from literals, and comments, a single internal ASCII space also appears in the following places only.

1. Separating any reserved word (such as if, for, or catch) from an open parenthesis (() that follows it on that line.

2. Separating any reserved word (such as else or catch) from a closing curly brace (}) that precedes it on that line.

3. Before any open curly brace ({), with two exceptions:

a. Before an object literal that is the first argument of a function or the first element in an array literal (e.g. foo({a: [{c: d}]})).

b. In a template expansion, as it is forbidden by the language (e.g. abc${1 + 2}def).

4. On both sides of any binary or ternary operator.

5. After a comma (,) or semicolon (;). Note that spaces are never allowed before these characters.

6. After the colon (:) in an object literal.

Version 4.0 28 of 99 9/15/2025

7. After the slash-asterisk (/*) or the double slash (//) that begins a block comment.

8. On both sides of the double slash (//) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required.

4.6.3 Function arguments

Prefer to put all function arguments on the same line as the function name. If doing so would exceed the 120-column limit, the arguments must be line-wrapped in a readable way. To save space, you may wrap as close to 120 as possible, or put each argument on its own line to enhance readability. Indentation should be four spaces. Aligning to the parenthesis is allowed, but discouraged. Below are the most common patterns for argument wrapping:

Function arguments

// Arguments start on a new line, indented using spaces. Preferred when the // arguments don't fit on the same line with the function name (or the keyword // "function") but fit entirely on the second line. Works with very long // function names, survives renaming without reindenting, low on space.

doSomething( descriptiveArgumentOne, descriptiveArgumentTwo, descriptiveArgumentThree) {

// If the argument list is longer, wrap at 120. Uses less vertical space, // but violates the rectangle rule and is thus not recommended.

doSomething(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {

// Two-space, one argument per line. Works with long function names, // survives renaming, and emphasizes each argument.

doSomething( veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {

Version 4.0 29 of 99 9/15/2025

4.7 Grouping parentheses: recommended

Optional grouping parentheses are omitted only when the author and reviewer agree that there is no reasonable chance that the code will be misinterpreted without them, nor would they have made the code easier to read. It is not reasonable to assume that every reader has the entire operator precedence table memorized.

Do not use unnecessary parentheses around the entire expression following delete, typeof, void, return, throw, case, in, of, or yield.In cases where type-checking doesn't accurately infer the type of an expression, it is possible to add a type cast comment by adding a type annotation comment and enclosing the expression in parentheses. The parentheses are required.

/** @type {number} */ (x)

5 Language features

This section delineates which features may or may not be used, and any additional constraints on their use.

5.1 Local variable declarations

5.1.1 Use const and let

Always use const or let to declare variables. Use const by default, unless a variable needs to be reassigned. Never use var.

Use const and let const foo = otherValue; // Use if "foo" never changes.

let bar = someValue; // Use if "bar" is ever assigned into later on.

const and let are block scoped, like variables in most other languages. var in JavaScript is function scoped, which can cause difficult to understand bugs. Don't use it.

Don’t use var

// ILLEGAL:

var foo = someValue; // Don't use - var scoping is complex and causes bugs.

Variables must not be used before their declaration.

Version 4.0 30 of 99 9/15/2025

5.1.2 One variable per declaration

Every local variable declaration declares only one variable: declarations such as let a = 1, b = 2; are not used.

5.2 Array literals

5.2.1 Do not use the Array constructor

Do not use the Array() constructor, with or without new. It has confusing and contradictory usage:

Do not use the variadic array constructor const a = new Array(2); // [undefined, undefined] const b = new Array(2, 3); // [2, 3];

// EXAMPLE:

Instead, always use bracket notation to initialize arrays, or from to initialize an Array with a certain size:

const a = [2];

const b = [2, 3];

// Equivalent to Array(2):

const c = [];

c.length = 2;

// [0, 0, 0, 0, 0]

Array.from<number>({length: 5}).fill(0);

5.2.2 Do not define properties on arrays

Do not define or use non-numeric properties on an array (other than length). Use a Map (or Object) instead.

5.2.3 Using spread syntax

Version 4.0 31 of 99 9/15/2025

Using spread syntax [...foo]; is a convenient shorthand for shallow-copying or concatenating iterables.

Using spread syntax const foo = [ 1, const foo2 = [ ...foo, 6, 7, const foo3 = [ 5, ...foo, foo2[1] === 6;

foo3[1] === 1;

[...foo] // preferred over Array.prototype.slice.call(foo) [...foo, ...bar] // preferred over foo.concat(bar)

When using spread syntax, the value being spread must match what is being created. When creating an array, only spread iterables. Primitives (including null and undefined) must not be spread.

Using spread syntax const foo = [7];

const bar = [5, ...(shouldUseFoo && foo)]; // might be undefined

// Creates {0: 'a', 1: 'b', 2: 'c'} but has no length const fooStrings = ['a', 'b', 'c'];

const ids = {...fooStrings};

// EXAMPLE:

const foo = shouldUseFoo ? [7] : [];

const bar = [5, ...foo];

const fooStrings = ['a', 'b', 'c'];

const ids = [...fooStrings, 'd', 'e'];

Version 4.0 32 of 99 9/15/2025

5.2.4 Array destructuring

Array literals may be used on the left-hand side of an assignment to perform destructuring (such as when unpacking multiple values from a single array or iterable). A final “rest” element may be included (with no space between the ... and the variable name). Elements should be omitted if they are unused.

Destructuring const [a, b, c, ...rest] = generateResults();

let [, b,, d] = someArray

Destructuring may also be used for function parameters. Always specify [] as the default value if a destructured array parameter is optional, and provide default values on the left hand side:

function optionalDestructuring([a = 4, b = 2] = []) {

// ILLEGAL:

function badDestructuring([a, b] = [4, 2]) {

Tip: For (un)packing multiple values into a function’s parameter or return, prefer object destructuring to array destructuring when possible, as it allows naming the individual elements and specifying a different type for each.

5.3 Object literals

5.3.1 Do not use the Object constructor

The Object constructor is disallowed. Use an object literal ({} or {a: 0, b: 1, c: 2}) instead.

5.3.2 Do not mix quoted and unquoted keys

Version 4.0 33 of 99 9/15/2025

Object literals may represent either structs (with unquoted keys and/or symbols) or dicts (with quoted and/or computed keys). Do not mix these key types in a single object literal.

Do not mix quoted and unquoted keys width: 42, // struct-style unquoted key 'maxWidth': 43, // dict-style quoted key

/* This also extends to passing the property name to functions, like hasOwnProperty. In particular, doing so will break in compiled code because the compiler cannot rename/obfuscate the string literal.*/

// ILLEGAL:

/** @type {{width: number, maxWidth: (number|undefined)}} */ const o = { width: 42 };

if (o.hasOwnProperty('maxWidth')) {

// best implemented as:

/** @type {{width: number, maxWidth: (number|undefined)}} */ const o = { maxWidth: 42 };

if (o.maxWidth !== null) {

5.3.3 Iterating objects

Iterating objects with for (... in ...) is error prone. It will include enumerable properties from the prototype chain.

Do not use unfiltered for (... in ...) statements:

Version 4.0 34 of 99 9/15/2025

Iterating objects

// AVOID:

for (const x in someObj) { // x could come from some parent prototype!

Either filter values explicitly with an if statement, or use for (... of Object.keys(...)).

Iterating objects for (const x in someObj) { if (!someObj.hasOwnProperty(x)) continue;

// now x was definitely defined on someObj for (const x of Object.keys(someObj)) { // note: for _of_!

// now x was definitely defined on someObj for (const [key, value] of Object.entries(someObj)) { // note: for _of_!

// now key was definitely defined on someObj

5.3.4 Using spread syntax

Using spread syntax {...bar} is a convenient shorthand for creating a shallow copy of an object.

When using spread syntax in object initialization, later values replace earlier values at the same key.

Spread syntax const foo = { num: 1, const foo2 = { ...foo, num: 5, const foo3 = { num: 5, ...foo, foo2.num === 5;

Version 4.0 35 of 99 9/15/2025 foo3.num === 1;

When using spread syntax, the value being spread must match what is being created. That is, when creating an object, only objects may be spread; arrays and primitives (including null and undefined) must not be spread.

const foo = {num: 7};

const bar = {num: 5, ...(shouldUseFoo && foo)}; // might be undefined

// Creates {0: 'a', 1: 'b', 2: 'c'} but has no length const fooStrings = ['a', 'b', 'c'];

const ids = {...fooStrings};

const foo = shouldUseFoo ? [7] : [];

const bar = [5, ...foo];

5.3.5 Computed property names

Computed property names (e.g. {['key' + foo()]: 42}) are allowed, and are considered dict-style (quoted) keys (i.e., must not be mixed with non-quoted keys) unless the computed property is a symbol (e.g. [Symbol.iterator]).

5.3.6 Method shorthand

Methods can be defined on object literals using the method shorthand ({method() {…}}) in place of a colon immediately followed by a function or arrow function literal.

Method shorthand return { stuff: 'candy', method() { return this.stuff; // Returns 'candy'

Version 4.0 36 of 99 9/15/2025

Note that this in a method shorthand or function refers to the object literal itself whereas this in an arrow function refers to the scope outside the object literal.

Method shorthand class { getObjectLiteral() { this.stuff = 'fruit';

return { stuff: 'candy', method: () => this.stuff, // Returns 'fruit'

5.3.7 Shorthand properties

Shorthand properties are allowed on object literals.

Shorthand properties const foo = 1;

const bar = 2;

const obj = { foo, bar, method() { return this.foo + this.bar;

assertEquals(3, obj.method());

5.3.8 Object destructuring

Object destructuring patterns may be used on the left-hand side of an assignment to perform destructuring and unpack multiple values from a single object.

Destructured objects may also be used as function parameters, but should be kept as simple as possible: a single level of unquoted shorthand properties. Deeper levels of nesting and computed properties may not be used in parameter destructuring. Specify any default values in the left-hand-side of the destructured parameter ({str = 'some default'} = {}, rather than {str} = {str:

'some default'}), and if a destructured object is itself optional, it must default to {}.

Version 4.0 37 of 99 9/15/2025

// EXAMPLE:

interface Options { /** The number of times to do something. */ num?: number;

/** A string to do stuff to. */ str?: string;

function destructured({num, str = 'default'}: Options = {}) {}

// ILLEGAL:

function nestedTooDeeply({x: {num, str}}: {x: Options}) {} function nonShorthandProperty({num: a, str: b} = {}) {};

function computedKey({a, b, [a + b]: c}) {};

function nontrivialDefault({num, str}: Options = {num: 42, str: 'default'}) {}

5.3.9 Enums

Enumerations are defined by adding properties to an object literal. Additional properties may not be added to an enum after it is defined. Enums must be constant, and all enum values must be deeply immutable.

Enums

* Supported temperature scales.

const TemperatureScale = { CELSIUS: 'celsius', FAHRENHEIT: 'fahrenheit',

* An enum with two options.

const Option = {

/** The option used shall have been the first. */

FIRST_OPTION: 1,

/** The second among two options. */

SECOND_OPTION: 2,

Version 4.0 38 of 99 9/15/2025

Enums

5.4 Classes

5.4.1 Class declarations

Class declarations must not be terminated with semicolons:

Class declarations

// EXAMPLE:

class Foo {

// ILLEGAL:

class Foo { }; // Unnecessary semicolon

In contrast, statements that contain class expressions must be terminated with a semicolon:

Class declarations

// EXAMPLE:

export const Baz = class extends Bar { method(): number { return this.x;

}; // Semicolon here as this is a statement, not a declaration

// ILLEGAL:

exports const Baz = class extends Bar { method(): number { return this.x;

It is neither encouraged nor discouraged to have blank lines separating class declaration braces from other class content:

Version 4.0 39 of 99 9/15/2025

Class declarations

// EXAMPLE:

// No spaces around braces - fine.

class Baz { method(): number { return this.x;

// A single space around both braces - also fine.

class Foo { method(): number { return this.x;

5.4.2 Class method declarations

Class method declarations must not use a semicolon to separate individual method declarations:

Class method declarations

// EXAMPLE:

class Foo { doThing() { console.log("A");

// ILLEGAL:

class Foo { doThing() { console.log("A");

}; // <-- unnecessary

Method declarations should be separated from surrounding code by a single blank line:

Version 4.0 40 of 99 9/15/2025

Class method declarations

// EXAMPLE:

class Foo { doThing() { console.log("A");

getOtherThing(): number { return 4;

// AVOID:

class Foo { doThing() { console.log("A");

getOtherThing(): number { return 4;

5.4.2.1 Overriding toString

The toString method may be overridden, but must always succeed and never have visible side effects.

Tip: Beware, in particular, of calling other methods from toString, since exceptional conditions could lead to infinite loops.

5.4.3 Static methods

5.4.3.1 Avoid private static methods

Where it does not interfere with readability, prefer module-local functions over private static methods.

5.4.3.2 Do not rely on dynamic dispatch

Code should not rely on dynamic dispatch of static methods. Static methods should only be called on the base class itself (which defines it directly). Static methods should not be called on variables containing a dynamic instance that may be either the constructor or a subclass constructor (and must be defined with @nocollapse if this is done), and must not be called directly on a subclass that doesn’t define the method itself.

Version 4.0 41 of 99 9/15/2025

Static methods

// ILLEGAL:

// Context for the examples below (this class is okay by itself) class Base { /** @nocollapse */ static foo() {} class Sub extends Base {}

// Discouraged: don't call static methods dynamically function callFoo(cls: typeof Base) { cls.foo();

// Disallowed: don't call static methods on subclasses that don't define it themselves Sub.foo();

// Disallowed: don't access this in static methods.

class MyClass { static foo() { return this.staticField;

MyClass.staticField = 1;

5.4.3.3 Avoid static this references

Code must not use this in a static context.

JavaScript/TypeScript allows accessing static fields through this. Different from other languages, static fields are also inherited.

Static methods

// ILLEGAL:

class ShoeStore { static storage: Storage = ...;

static isAvailable(s: Shoe) { // Bad: do not use `this` in a static method.

return this.storage.has(s.id);

class EmptyShoeStore extends ShoeStore { static storage: Storage = EMPTY_STORE; // overrides storage from ShoeStore

Version 4.0 42 of 99 9/15/2025

This code is generally surprising: authors might not expect that static fields can be accessed through the this pointer, and might be surprised to find that they can be overridden - this feature is not commonly used.

This code also encourages an anti-pattern of having substantial static state, which causes problems with testability.

5.4.4 Constructors

Constructor calls must use parentheses, even when no arguments are passed:

Constructors

// ILLEGAL:

const x = new Foo;

// EXAMPLE:

const x = new Foo();

// Omitting parentheses can lead to subtle mistakes. These two lines are not equivalent:

new Foo().Bar();

new Foo.Bar();

It is unnecessary to provide an empty constructor or one that simply delegates into its parent class because ES2015 provides a default class constructor if one is not specified. However constructors with parameter properties, visibility modifiers or parameter decorators should not be omitted even if the body of the constructor is empty.

Constructors

// ILLEGAL:

class UnnecessaryConstructor { constructor() {} class UnnecessaryConstructorOverride extends Base { constructor(value: number) { super(value);

// EXAMPLE:

class DefaultConstructor {

Version 4.0 43 of 99 9/15/2025

Constructors class ParameterProperties { constructor(private myService) {} class ParameterDecorators { constructor(@SideEffectDecorator myService) {} class NoInstantiation { private constructor() {}

The constructor should be separated from surrounding code both above and below by a single blank line:

Constructors

// EXAMPLE:

class Foo { myField = 10;

constructor(priv…

This is the start of the file's text. The full file is on GovTribe.

File details come from the government source that posted it. Updated .