### Good Identifier Examples in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates correctly formatted identifiers in TypeScript, adhering to descriptive naming and standard conventions. These examples show how to name variables and properties clearly. ```typescript // Good identifiers: errorCount // No abbreviation. dnsConnectionIndex // Most people know what "DNS" stands for. referrerUrl // Ditto for "URL". customerId // "Id" is both ubiquitous and unlikely to be misunderstood. ``` -------------------------------- ### TypeScript Decorator Usage Example Source: https://google.github.io/styleguide/tsguide.html/index Shows the correct syntax for using decorators in TypeScript, emphasizing that they should immediately precede the symbol they decorate without intervening empty lines. This example includes JSDoc comments and demonstrates decorators on classes and fields. ```typescript /** JSDoc comments go before decorators */ @Component({...}) // Note: no empty line after the decorator. class MyComp { @Input() myField: string; // Decorators on fields may be on the same line... @Input() myOtherField: string; // ... or wrap. } ``` -------------------------------- ### Brewing Coffee with Parameter Documentation Source: https://google.github.io/styleguide/tsguide.html/index Example of documenting a method that adds information beyond the parameter name and type. The '@param' annotation is used here to clarify the 'amountLitres' parameter. ```typescript /** * POSTs the request to start coffee brewing. * @param amountLitres The amount to brew. Must fit the pot size! */ brew(amountLitres: number, logger: Logger) { // ... } ``` -------------------------------- ### Parameter Initializers (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the use of default initializers for optional function parameters in TypeScript. It emphasizes that initializers should not have side effects and should be kept simple. Examples of both correct and incorrect usage are provided. ```typescript function process(name: string, extraContext: string[] = []) {} function activate(index = 0) {} ``` ```typescript // BAD: side effect of incrementing the counter let globalCounter = 0; function newId(index = globalCounter++) {} // BAD: exposes shared mutable state, which can introduce unintended coupling // between function calls class Foo { private readonly defaultPaths: string[]; frobnicate(paths = defaultPaths) {} } ``` -------------------------------- ### Disallowed Identifier Examples in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates identifiers that violate TypeScript naming conventions, including ambiguous abbreviations, unfamiliar abbreviations, and incorrect casing. These examples highlight common pitfalls to avoid. ```typescript // Disallowed identifiers: n // Meaningless. nErr // Ambiguous abbreviation. nCompConns // Ambiguous abbreviation. wgcConnections // Only your group knows what this stands for. pcReader // Lots of things can be abbreviated "pc". cstmrId // Deletes internal letters. kSecondsPerDay // Do not use Hungarian notation. customerID // Incorrect camelcase of "ID". ``` -------------------------------- ### TypeScript Indexable Type Syntax Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the use of index signatures in TypeScript to type objects used as associative arrays (maps, hashes, dicts). It shows how to provide a meaningful label for the key for documentation purposes, although this label is not used at runtime. The examples highlight the basic syntax and the improved version with a descriptive key label. ```typescript const fileSizes: {[fileName: string]: number} = {}; fileSizes['readme.txt'] = 541; ``` ```typescript const users: {[key: string]: number} = ...; ``` ```typescript const users: {[userName: string]: number} = ...; ``` -------------------------------- ### Event Handlers with Arrow Functions (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index Explains how to use arrow functions for event handlers in TypeScript, especially when uninstallation is not required or when a stable reference is needed for uninstallation. It also warns against using `bind` directly in event listener installation. ```typescript // Event handlers may be anonymous functions or arrow function properties. class Component { onAttached() { // The event is emitted by this class, no need to uninstall. this.addEventListener('click', () => { this.listener(); }); // this.listener is a stable reference, we can uninstall it later. window.addEventListener('onbeforeunload', this.listener); } onDetached() { // The event is emitted by window. If we don't uninstall, this.listener will // keep a reference to `this` because it's bound, causing a memory leak. window.removeEventListener('onbeforeunload', this.listener); } // An arrow function stored in a property is bound to `this` automatically. private listener = () => { confirm('Do you want to exit the page?'); } } ``` ```typescript // Binding listeners creates a temporary reference that prevents uninstalling. class Component { onAttached() { // This creates a temporary reference that we won't be able to uninstall window.addEventListener('onbeforeunload', this.listener.bind(this)); } onDetached() { // This bind creates a different reference, so this line does nothing. window.removeEventListener('onbeforeunload', this.listener.bind(this)); } private listener() { confirm('Do you want to exit the page?'); } } ``` -------------------------------- ### Rest and Spread Syntax in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the correct usage of rest and spread syntax in TypeScript functions and calls. Ensures no space after the '...' operator. ```typescript function myFunction(...elements: number[]) {} myFunction(...array, ...iterable, ...generator()); ``` -------------------------------- ### Basic JSDoc Comment Structure in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the general form of JSDoc comments for functions in TypeScript, including multi-line and single-line examples. JSDoc comments are used for user-facing documentation and are parsed by tools. ```typescript /** * Multiple lines of JSDoc text are written here, * wrapped normally. * @param arg A number to do something to. */ function doSomething(arg: number) { … } ``` ```typescript /** This short jsdoc describes the function. */ function doSomething(arg: number) { … } ``` -------------------------------- ### Documenting Parameter Properties in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how to document parameter properties using JSDoc's '@param' annotation. This ensures that descriptions are displayed on constructor calls and property accesses. ```typescript /** This class demonstrates how parameter properties are documented. */ class ParamProps { /** * @param percolator The percolator used for brewing. * @param beans The beans to brew. */ constructor( private readonly percolator: Percolator, private readonly beans: CoffeeBean[]) {} } ``` -------------------------------- ### Component Documentation Before Decorators Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the correct placement of JSDoc comments when a class has decorators. The documentation should always precede the decorator. ```typescript /** Component that prints "bar". */ @Component({ selector: 'foo', template: 'bar', }) export class FooComponent {} ``` -------------------------------- ### Providing Specific Types in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates how to replace the 'any' type with more specific and safer alternatives like declared interfaces, type aliases, inline object types, and generic types. ```typescript // Use declared interfaces to represent server-side JSON. declare interface MyUserJson { name: string; email: string; } // Use type aliases for types that are repetitive to write. type MyType = number|string; // Or use inline object types for complex returns. function getTwoThings(): {something: number, other: string} { // ... return {something, other}; } // Use a generic type, where otherwise a library would say `any` to represent // they don't care what type the user is operating on (but note "Return type // only generics" below). function nicestElement(items: T[]): T { // Find the nicest element in items. // Code can also put constraints on T, e.g. . } ``` -------------------------------- ### Spread Syntax for Function Calls (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index Shows how to use the spread syntax in TypeScript as a replacement for `Function.prototype.apply`. This allows for more concise and readable function calls when passing an array of arguments. ```typescript // Example demonstrating spread syntax instead of apply (conceptual) // const numbers = [1, 2, 3]; // Math.max(...numbers); // Equivalent to Math.max.apply(null, numbers); ``` -------------------------------- ### JSDoc Tag Formatting in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the correct formatting for JSDoc tags, specifically the 'param' tag, in TypeScript. Each tag must occupy its own line and cannot be combined. ```typescript /** * The "param" tag must occupy its own line and may not be combined. * @param left A description of the left param. * @param right A description of the right param. */ function add(left: number, right: number) { ... } ``` ```typescript /** * The "param" tag must occupy its own line and may not be combined. * @param left @param right */ function add(left: number, right: number) { ... } ``` -------------------------------- ### Suppressing `any` Lint Warnings in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how to suppress `no-any` lint warnings in TypeScript when using `any` is a legitimate, documented choice, such as in tests for creating mock objects. Includes examples of suppressing warnings for mock object creation and nullish type assertions. ```typescript // This test only needs a partial implementation of BookService, and if // we overlooked something the test will fail in an obvious way. // This is an intentionally unsafe partial mock // tslint:disable-next-line:no-any const mockBookService = ({get() { return mockBook; }} as any) as BookService; // Shopping cart is not used in this test // tslint:disable-next-line:no-any const component = new MyComponent(mockBookService, /* unused ShoppingCart */ null as any); ``` -------------------------------- ### Using 'this' in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the appropriate contexts for using the 'this' keyword in TypeScript, such as class constructors, methods, and explicitly typed functions or arrow functions. ```typescript this.alert('Hello'); ``` -------------------------------- ### Parsing Integers with Number() and Math.floor/trunc in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Presents the recommended approach for parsing integers in TypeScript: use `Number()` to convert the string to a number, check for `NaN`, and then use `Math.floor()` or `Math.trunc()` to get the integer part. This method is safer and more explicit. ```typescript let f = Number(someString); if (isNaN(f)) handleError(); f = Math.floor(f); ``` -------------------------------- ### Use Strict Equality (===) in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Highlights the importance of using strict equality operators (`===` and `!==`) in TypeScript to avoid error-prone type coercion. It provides an example of disallowed double equality and the preferred strict equality usage. ```typescript if (foo == 'bar' || baz != bam) { // Hard to understand behaviour due to type coercion. } if (foo === 'bar' || baz !== bam) { // All good here. } ``` -------------------------------- ### Documenting Ordinary Fields in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates how to document ordinary class fields that are not parameter properties. This involves using JSDoc comments directly above the field declaration. ```typescript /** This class demonstrates how ordinary fields are documented. */ class OrdinaryClass { /** The bean that will be used in the next call to brew(). */ nextBean: CoffeeBean; constructor(initialBean: CoffeeBean) { this.nextBean = initialBean; } } ``` -------------------------------- ### Fileoverview JSDoc in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the correct format for a fileoverview JSDoc comment at the top of a TypeScript file. This JSDoc should describe the file's content, uses, or dependencies. ```typescript /** * @fileoverview Description of file. Lorem ipsum dolor sit amet, consectetur * adipiscing elit, sed do eiusmod tempor incididunt. */ ``` -------------------------------- ### TypeScript Pick Type vs. Interface Extension Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how TypeScript's `Pick` utility type can be used to create a subset of an existing type, and compares it to using interface extension for better readability and IDE support. ```typescript interface User { shoeSize: number; favoriteIcecream: string; favoriteChocolate: string; } // FoodPreferences has favoriteIcecream and favoriteChocolate, but not shoeSize. type FoodPreferences = Pick; interface FoodPreferencesExplicit { favoriteIcecream: string; favoriteChocolate: string; } interface UserExtendsFoodPreferences extends FoodPreferencesExplicit { shoeSize: number; // also includes the preferences. } ``` -------------------------------- ### Constructor Spacing in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Constructors in TypeScript should be separated from surrounding code by a single blank line above and below. This improves code readability and organization. ```TypeScript class Foo { myField = 10; constructor(private readonly ctorParam) {} doThing() { console.log(ctorParam.getThing() + myField); } } ``` ```TypeScript class Foo { myField = 10; constructor(private readonly ctorParam) {} doThing() { console.log(ctorParam.getThing() + myField); } } ``` -------------------------------- ### Tuple Types vs. Pair Interface in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Shows how to use tuple types `[string, string]` as a more concise and type-safe alternative to defining a `Pair` interface for returning multiple values. Demonstrates usage with destructuring. ```typescript interface Pair { first: string; second: string; } function splitInHalf(input: string): Pair { ... return {first: x, second: y}; } ``` ```typescript function splitInHalf(input: string): [string, string] { ... return [x, y]; } // Use it like: const [leftHalf, rightHalf] = splitInHalf('my string'); ``` -------------------------------- ### Rest Parameters (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the use of rest parameters in TypeScript functions as a modern alternative to the `arguments` object. It shows how to define a function that accepts a variable number of arguments of a specific type. ```typescript function variadic(array: string[], ...numbers: number[]) {} ``` -------------------------------- ### Named Exports in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the recommended practice of using named exports for all code in TypeScript. This ensures a uniform import pattern and provides benefits like compile-time error checking for imported members. ```typescript // Use named exports: export class Foo { ... } ``` -------------------------------- ### Renaming Imports in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Shows how to rename imports in TypeScript to resolve name collisions, handle generated symbol names, or improve clarity for ambiguous imported symbol names. This can be achieved using the `as` keyword. ```typescript import { from as observableFrom } from 'rxjs'; // Usage of observableFrom would be clearer than just 'from' ``` -------------------------------- ### Handling Long Strings in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the recommended approach for handling long strings in TypeScript by using string concatenation instead of line continuations. This improves readability and avoids potential errors. ```typescript const LONG_STRING = 'This is a very very very very very very very long string. ' + 'It does not contain long stretches of spaces because it uses ' + 'concatenated strings.'; const SINGLE_STRING = 'http://it.is.also/acceptable_to_use_a_single_long_string_when_breaking_would_hinder_search_discoverability'; ``` -------------------------------- ### Function Call Comments: Legacy Style Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the legacy style for parameter name comments in function calls. These comments appear after the parameter value and omit the equals sign. ```javascript someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */); ``` -------------------------------- ### TypeScript 'unknown' Type for Type Safety Source: https://google.github.io/styleguide/tsguide.html/index Shows how to use the 'unknown' type in TypeScript as a safer alternative to 'any', preventing arbitrary property access and requiring type narrowing or casting for safe usage. ```typescript // Can assign any value (including null or undefined) into this but cannot // use it without narrowing the type or casting. const val: unknown = value; const danger: any = value; // result of an arbitrary expression danger.whoops(); // This access is completely unchecked! ``` -------------------------------- ### Throwing Errors with 'new Error()' (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index When instantiating exceptions in TypeScript, always use the 'new Error()' syntax. This is consistent with other object instantiation patterns and ensures proper error object creation. ```TypeScript throw new Error('Foo is not a valid bar.'); ``` -------------------------------- ### Multi-line Comments in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the correct and incorrect ways to use multi-line comments in TypeScript. Multi-line comments must use multiple single-line comments (`//`), not block comment style (`/* */`). ```typescript // This is // fine ``` ```typescript /* * This should * use multiple * single-line comments */ /* This should use // */ ``` -------------------------------- ### TypeScript Function Declarations vs. Arrow Functions Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the preference for using function declarations for named functions in TypeScript. Arrow functions are shown as an alternative, particularly when explicit type annotations are required. ```typescript function foo() { return 42; } ``` ```typescript const foo = () => 42; ``` ```typescript interface SearchFunction { (source: string, subString: string): boolean; } const fooSearch: SearchFunction = (source, subString) => { ... }; ``` -------------------------------- ### TypeScript Disallowed Wrapper Objects Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the incorrect instantiation of wrapper objects for primitive types in TypeScript. Creating `new String()`, `new Boolean()`, or `new Number()` can lead to unexpected behavior and should be avoided. ```typescript const s = new String('hello'); const b = new Boolean(false); const n = new Number(5); ``` -------------------------------- ### Module namespace import casing in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the convention for module namespace imports in TypeScript, where they should be lowerCamelCase, contrasting with file names which should be snake_case. It also notes exceptions for common libraries like jQuery and Three.js. ```typescript import * as fooBar from './foo_bar'; ``` -------------------------------- ### Line Wrapping for JSDoc Descriptions in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates proper line wrapping for long JSDoc parameter and return descriptions in TypeScript. Wrapped text should be indented four spaces, though horizontal alignment is discouraged. ```typescript /** * Illustrates line wrapping for long param/return descriptions. * @param foo This is a param with a particularly long description that just * doesn't fit on one line. * @return This returns something that has a lengthy description too long to fit * in one line. */ exports.method = function(foo) { return 5; }; ``` -------------------------------- ### Avoid Array Constructor in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Do not use the `Array()` constructor. Instead, use bracket notation `[]` for array initialization or `Array.from()` for creating arrays with a specific size. This avoids confusing and contradictory usage patterns. ```typescript const a = [2]; const b = [2, 3]; // Equivalent to Array(2): const c = []; c.length = 2; // [0, 0, 0, 0, 0] Array.from({length: 5}).fill(0); ``` -------------------------------- ### Class Declaration Syntax in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the correct syntax for TypeScript class declarations, emphasizing that they must not be terminated with semicolons. It contrasts this with class expressions within statements, which must be terminated with a semicolon. ```typescript // Correct: class Foo { } // Incorrect: // class Foo { // }; // Unnecessary semicolon // Correct for statements containing class expressions: export const Baz = class extends Bar { method(): number { return this.x; } }; // Semicolon here as this is a statement, not a declaration // Incorrect: // exports const Baz = class extends Bar { // method(): number { // return this.x; // } // } ``` -------------------------------- ### Use 'as' Syntax for Type Assertions in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Mandates the use of the `as` keyword for type assertions in TypeScript, rather than the older angle-bracket syntax. This syntax requires parentheses when accessing members, improving clarity. ```typescript // z must be Foo because ... const x = (z as Foo).length; ``` -------------------------------- ### Parameter Properties in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Use TypeScript parameter properties as a concise alternative to plumbing initializers to class members. This reduces boilerplate code, especially when the constructor's primary role is to assign parameters to properties. ```TypeScript class Foo { private readonly barService: BarService; constructor(barService: BarService) { this.barService = barService; } } ``` ```TypeScript class Foo { constructor(private readonly barService: BarService) {} } ``` -------------------------------- ### Class Method Declaration Syntax in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Details the syntax for class method declarations in TypeScript. It specifies that semicolons should not be used to separate individual method declarations and that methods should be separated by a single blank line for readability. ```typescript // Correct: class Foo { doThing() { console.log("A"); } getOtherThing(): number { return 4; } } // Incorrect: // class Foo { // doThing() { // console.log("A"); // }; // } ``` -------------------------------- ### TypeScript Disallowed Debugger Statement Source: https://google.github.io/styleguide/tsguide.html/index Shows an example of a disallowed `debugger;` statement within production code. Debugger statements should only be used during development and debugging phases and must be removed before deployment. ```typescript function debugMe() { debugger; } ``` -------------------------------- ### TypeScript Import Paths Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the preferred methods for specifying import paths in TypeScript, favoring relative paths (`./foo`, `../parent/file`) over absolute paths (`path/from/root`) for better project portability. It also advises limiting the use of deep relative paths. ```typescript import {Symbol1} from 'path/from/root'; import {Symbol2} from '../parent/file'; import {Symbol3} from './sibling'; ``` -------------------------------- ### Avoid Mutable Exports in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Mutable exports, especially with `export let`, can lead to hard-to-debug code. This example shows the problematic `export let` and the recommended approach using explicit getter functions. ```typescript 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. window.setTimeout(() => { foo = 4; }, 1000 /* ms */); let foo = 3; window.setTimeout(() => { foo = 4; }, 1000 /* ms */); // Use an explicit getter to access the mutable export. export function getFoo() { return foo; }; ``` -------------------------------- ### Handling Nullable Types in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how to correctly define and use nullable types in TypeScript. It shows the preferred method of adding `|undefined` or `|null` at the usage site rather than in type aliases, and how optional parameters/fields implicitly handle `undefined`. ```typescript // Bad practice: Including null/undefined in type aliases type CoffeeResponse = Latte|Americano|undefined; class CoffeeService { getLatte(): CoffeeResponse { ... }; } ``` ```typescript // Better practice: Adding null/undefined at the usage site type CoffeeResponse = Latte|Americano; class CoffeeService { getLatte(): CoffeeResponse|undefined { ... }; } ``` ```typescript // Using optional fields and parameters interface CoffeeOrder { sugarCubes: number; milk?: Whole|LowFat|HalfHalf; // Optional field } function pourCoffee(volume?: Milliliter) { ... } // Optional parameter ``` ```typescript // Preferring initialization over optional fields in classes class MyClass { field = ''; // Initialized field } ``` -------------------------------- ### Control Flow Statements with Braced Blocks (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index Control flow statements like 'if', 'else', and 'for' must always use braced blocks for their containing code, even for single statements. The first statement within a non-empty block should start on a new line. ```TypeScript for (let i = 0; i < x; i++) { doSomethingWith(i); } if (x) { doSomethingWithALongMethodNameThatForcesANewLine(x); } ``` -------------------------------- ### Handle Exceptions with Comments in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the correct way to handle exceptions in TypeScript when an empty catch block is necessary. A comment must explain why no action is taken, providing context for future developers. It also shows a disallowed empty catch block. ```typescript try { return handleNumericResponse(response); } catch (e: unknown) { // Response is not numeric. Continue to handle as text. } return handleTextResponse(response); ``` -------------------------------- ### Field Initializers in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Initialize class members where they are declared if they are not parameter properties. This can sometimes eliminate the need for a constructor entirely, simplifying class definitions. ```TypeScript class Foo { private readonly userList: string[]; constructor() { this.userList = []; } } ``` ```TypeScript class Foo { private readonly userList: string[] = []; } ``` -------------------------------- ### Catch and Rethrow Errors Safely in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how to safely catch and rethrow errors in TypeScript, ensuring that only instances of `Error` are handled. It includes a helper function `assertIsError` and shows how to handle non-Error types with a comment explaining the deviation. ```typescript function assertIsError(e: unknown): asserts e is Error { if (!(e instanceof Error)) throw new Error("e is not an Error"); } try { doSomething(); } catch (e: unknown) { // All thrown errors must be Error subtypes. Do not handle // other possible values unless you know they are thrown. assertIsError(e); displayError(e.message); // or rethrow: throw e; } try { badApiThrowingStrings(); } catch (e: unknown) { // Note: bad API throws strings instead of errors. if (typeof e === 'string') { ... } } ``` -------------------------------- ### Named Imports for Apps JSPB Protos in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Illustrates the specific requirement for Apps JSPB protos to use named imports, even for long import lines. This practice aids build performance and dead code elimination by allowing finer-grained dependencies on messages within `.proto` files. ```typescript // 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) {...} ``` -------------------------------- ### Conditional Exports in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index For conditionally exporting values, perform the check first and then assign the result to a `const` export. This ensures all exports are final after module execution. ```typescript function pickApi() { if (useOtherApi()) return OtherApi; return RegularApi; } export const SomeApi = pickApi(); ``` -------------------------------- ### Justify Unsafe Type Assertions in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Explains that when type assertions (`as Type`) or non-nullability assertions (`!`) are unavoidable, a comment should clarify why the assertion is considered safe in that specific context. ```typescript // x is a Foo, because ... (x as Foo).foo(); // y cannot be null, because ... y!.bar(); ``` -------------------------------- ### One Variable Per Declaration in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Each local variable declaration should declare only a single variable. Avoid combined declarations like `let a = 1, b = 2;`. -------------------------------- ### Avoid Container Classes for Namespacing in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Do not use container classes with static methods or properties solely for namespacing. Instead, export individual constants and functions directly. ```typescript // Bad: Container class for namespacing export class Container { static FOO = 1; static bar() { return 1; } } // Good: Export individual members export const FOO = 1; export function bar() { return 1; } ``` -------------------------------- ### Use Unicode Characters and Special Escape Sequences in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the correct usage of Unicode characters and special escape sequences for characters like 'μ' and the byte order mark (BOM) in TypeScript. It contrasts clear, readable code with less understandable escaped versions. ```typescript // Perfectly clear, even without a comment. const units = 'μs'; // Use escapes for non-printable characters. const output = '\ufeff' + content; // byte order mark ``` ```typescript // 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; ``` -------------------------------- ### Numeric Parsing with Number() in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates the recommended method for parsing numeric values using `Number()`. It's crucial to explicitly check the return value for `NaN` or non-finite numbers using `isFinite()` to handle potential parsing errors or overflows. ```typescript const aNumber = Number('123'); if (!isFinite(aNumber)) throw new Error(...); ``` -------------------------------- ### Ignoring elements during array destructuring in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Demonstrates how to use extra commas in a destructuring assignment to ignore specific elements from an array or tuple. This is useful when only a subset of values is needed. ```typescript const [a, , b] = [1, 5, 10]; // a <- 1, b <- 10 ``` -------------------------------- ### Exporting Types in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Employ `export type` when re-exporting a type. This is particularly useful for enabling type re-exports in file-by-file transpilation scenarios, as supported by the `isolatedModules` compiler option. ```typescript export type {AnInterface} from './foo'; ``` -------------------------------- ### TypeScript Focused Try Blocks for Error Handling Source: https://google.github.io/styleguide/tsguide.html/index Illustrates how to keep try blocks focused by limiting the code within them. This improves readability by clearly indicating which operations might throw exceptions. Moving non-throwing code outside the try block helps readers identify potential error sources. ```typescript try { const result = methodThatMayThrow(); use(result); } catch (error: unknown) { // ... handle error ... } ``` ```typescript let result; try { result = methodThatMayThrow(); } catch (error: unknown) { // ... handle error ... } use(result); ``` -------------------------------- ### Markdown Formatting within JSDoc in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Shows how to correctly use Markdown formatting within JSDoc comments in TypeScript to ensure proper rendering by documentation tools. Plain text formatting is ignored; use Markdown lists for clarity. ```typescript /** * Computes weight based on three factors: * items sent * items received * last timestamp */ ``` ```typescript /** * Computes weight based on three factors: * * - items sent * - items received * - last timestamp */ ``` -------------------------------- ### Intentional Assignment in Control Statements (TypeScript) Source: https://google.github.io/styleguide/tsguide.html/index When assignment within a control statement is intentional and necessary, enclose the assignment expression in additional parentheses. This clearly indicates the assignment is deliberate and not a mistake. ```TypeScript while ((x = someFunction())) { // Double parenthesis shows assignment is intentional // ... } ``` -------------------------------- ### TypeScript Import Statements Source: https://google.github.io/styleguide/tsguide.html/index Shows various valid ways to import modules and specific exports in TypeScript, including namespace imports, named imports, default imports, and side-effect imports. It emphasizes using the appropriate import type based on the module's structure and intended use. ```typescript // 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'; ``` -------------------------------- ### Enum to Boolean Coercion in TypeScript (Recommended) Source: https://google.github.io/styleguide/tsguide.html/index Shows the recommended way to handle enum values in boolean contexts by explicitly comparing them with comparison operators. This avoids the potential confusion arising from implicit boolean coercion of enum values. ```typescript enum SupportLevel { NONE, BASIC, ADVANCED, } const level: SupportLevel = ...; let enabled = level !== SupportLevel.NONE; const maybeLevel: SupportLevel|undefined = ...; enabled = level !== undefined && level !== SupportLevel.NONE; ``` -------------------------------- ### Avoid Object Constructor in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index The `Object` constructor is disallowed. Always use object literals (`{}`) for object creation. This ensures clarity and avoids potential issues associated with constructor usage. ```typescript const obj = { a: 1, b: 2 }; ``` -------------------------------- ### Static Method Usage and Restrictions in TypeScript Source: https://google.github.io/styleguide/tsguide.html/index Provides guidelines for using static methods in TypeScript, discouraging reliance on dynamic dispatch and advocating for module-local functions over private static methods where readability is not compromised. It also prohibits the use of `this` in static contexts. ```typescript // 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; // Avoid static `this` references 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 } ```