---
# System prepended metadata

title: Code style guide

---

# Code style guide

## Table of Contents

1. [Naming](#naming)
2. [Style](#style)
3. [General and Generic Types](#general-and-generic-types)
4. [Declarations](#declarations)

# Naming

## type names and interfaces

- Use PascalCase

```ts
// ✗ avoid
type nameResolver = () => string;
// ✓ good
type NameResolver = () => string;
interface NameResolver {
  (): string;
}
```

## Enum values and initializers

- Use PascalCase
- There will be no intersection with variable names. Let's look at this:

  ```ts
  // ✗ avoid
  enum fileAccess {
    none,
    READ = 1 << 1,
  }
  function readFile(fileAccess: fileAccess) {
    // Compilation error:
    //   * Property 'none' does not exist on type 'fileAccess'.
    if (fileAccess === fileAccess.none) {
    }
  }
  ```

  And this:

  ```ts
  // ✓ good
  enum FileAccess {
    None,
    Read = 1 << 1,
  }
  function readFile(fileAccess: FileAccess) {
    if (fileAccess === FileAccess.None) {
    }
  }
  ```

  Google, Microsoft, Facebook, airbnb and other companies encourage this rule.

## Function names, class properties and local variables

- Use camelCase
- Use the appropriate prefix if the subsequent expression is of type boolean or the function declaration that returns boolean value:

  ```ts
  function shouldDownloadXML(): boolean {
    return true;
  }
  function canBePushedIntoArray(): boolean {
    return true;
  }
  const isBrowser = typeof window !== 'undefined';
  ```

  Google, Microsoft, Facebook, airbnb and other companies encourage this rule.

## Interface naming

- Do not use "I" as a prefix for interface names:

  ```ts
  interface IPerson {} // ✗ avoid
  interface Person {} // ✓ good
  ```

  Microsoft official guidelines, all world TypeScript coding standards and books discourage the `I` prefix. Links:

* [Microsoft guidelines](https://github.com/microsoft/TypeScript/wiki/Coding-guidelines#names)
* [Basarat TypeScript book](https://github.com/basarat/typescript-book/blob/master/docs/styleguide/styleguide.md#interface) (this is the most popular in the TypeScript world)
* [Learn TypeScript 3 by Building Web Applications](https://subscription.packtpub.com/book/programming/9781789615869/3/ch03lvl1sec37/typescript-interfaces)

  ```ts
  interface ICar {
    speed: number;
    move(): void;
  }
  class Car implements ICar {
    speed = 100;
    move() {}
  }
  ```

  The thing is that classes and interfaces should be thought of as interchangeable when passed as types. In theory there is no reason to know that a reference of type `Car` refers to a class and not an interface. Anders Hejlsberg is the creator of C# and TypeScript, he also created guidelines for the TypeScript where he discourages the `I` prefix.

  `ICar + Car` is an antipattern, means the interface basically has 1 implementation, which means there shouldn't be an interface at all. You would want specific, concrete identifiers for your implementation, concrete classes, e.g. `SportsCar implements Car`, `SUVCar implements Car` etc. Some other examples: interface `PaymentProcessor` and concrete class `CreditCardPaymentProcessor` instead of `IPaymentProcessor` and `PaymentProcessor`.

## Do not use non-common acronyms and unnecessary abbreviations

- Use whole words in names when possible:
  ```ts
  // ✗ avoid
  const msg = 'Hello!';
  const appSvc = new AppSvc();
  // ✓ good
  const message = 'Hello!';
  const appService = new AppService();
  ```

## Do not prefix with underscore

- Do not use "\_" as a prefix for private properties:

  ```ts
  // ✗ avoid
  export class AddressComponent {
    private _dialogWidth = 400;
    private _showDialog() {}
  }
  // ✓ good
  export class AddressComponent {
    private dialogWidth = 400;
    private showDialog() {}
  }
  ```

  Why?

- JavaScript lacks a true private property or method.
- TypeScript tooling makes it easy to identify private vs. public properties and methods.

  Google, Microsoft, Facebook, airbnb and other companies encourage this rule.

# Style

## Consider using `const enum`

- enums that do not require "lookup object" can be turned into `const enum` which is not compiled into objects and inlined instead.

  ```ts
  enum FileAccess {
    None,
    Read = 1 << 1,
  }
  function getReadFileAccess() {
    return FileAccess.Read;
  }
  // Compiled code
  var FileAccess;
  (function (FileAccess) {
    FileAccess[(FileAccess['None'] = 0)] = 'None';
    FileAccess[(FileAccess['Read'] = 2)] = 'Read';
  })(FileAccess || (FileAccess = {}));
  function getReadFileAccess() {
    return FileAccess.Read;
  }
  ```

  Using `const enum`:

  ```ts
  const enum FileAccess {
    None,
    Read = 1 << 1,
  }
  function getReadFileAccess() {
    return FileAccess.Read;
  }
  // Compiled code
  function getReadFileAccess() {
    return 2 /* Read */;
  }
  ```

## Return Early Pattern

- Consider using the "Return Early Pattern" to avoid nested code blocks thus making the code easier to read in general:

  ```ts
  class CreateBookComponent {
    form = new FormGroup({ ... });

    constructor(private booksService: BooksService) {}

    createBook(): void {
      // ✗ avoid
      if (this.form.valid) {
        this.booksService.createBook(this.form.value).subscribe(() => {
          this.form.reset();
        });
      }

      // ✓ good
      if (this.form.invalid) {
        return;
      }

      this.booksService.createBook(this.form.value).subscribe(() => {
        this.form.reset();
      });
    }
  }
  ```

# General and Generic Types

## Infer types of variables/constants

- Allow the compiler to infer types of variables itself:
  ```ts
  // ✗ avoid
  const warning: string = 'Hey, this is some warning...';
  // ✓ good
  const warning = 'Hey, this is some warning...';
  ```

## Avoid `any` as much as possible

- imagine there is no `any` type. Try to replace it with actual typing if possible or `unknown` if type is really unknown.

## Prefer type value or extend instead of `any` in generics

- When declaring type variables don't allow the compiler to accept the `any` type as a default value. Limit type inference:
  ```ts
  interface User {}
  interface Issuer extends User {}
  interface Investor extends User {}
  // ✗ avoid
  class UserCreditCardPaymentProcessor<T = any> {
    constructor(public user: T) {}
  }
  // ✓ good
  class UserCreditCardPaymentProcessor<T extends User> {
    constructor(public user: T) {}
  }
  ```
- Require to provide type values:
  ```ts
  type RequireGeneric<T, U> = T extends void ? 'Provide a type variable' : U;
  interface User {}
  interface Issuer extends User {}
  interface Investor extends User {}
  class UserCreditCardPaymentProcessor<T = void> {
    constructor(public user: RequireGeneric<T, User>) {}
  }
  // Compilation error
  new UserCreditCardPaymentProcessor({});
  // Successful compilation
  new UserCreditCardPaymentProcessor<Issuer>({});
  ```

## Specify type guards

- Consider using user-defined type guards to narrow type inference. Type guards provide the ability to narrow a variable type inside `if` blocks. The cornerstones of type guards were `typeof` and `instanceof` operators. User-defined type guards are simply functions that return type predicates, let's look at the below code:

  ```ts
  // `el is Element` is a type predicate
  function isElement(el: Node | null): el is Element {
    return el !== null && el.nodeType === Node.ELEMENT_NODE;
  }
  function isAnchorElement(el: Node | null): el is HTMLAnchorElement {
    return isElement(el) && el.nodeName === 'A';
  }
  function isImageElement(el: Node | null): el is HTMLImageElement {
    return isElement(el) && el.nodeName === 'IMG';
  }
  function isFrameElement(el: Node | null): el is HTMLFrameElement {
    return isElement(el) && el.nodeName === 'IFRAME';
  }
  function updateUrl(el: Node | null, url: string): void {
    // Compilation errors:
    //   * Object is possibly 'null'.
    //   * Property 'href' does not exist on type 'Node'.
    el.href = url;
    if (el !== null && 'href' in el) {
      // Compilation error: Property 'href' does not exist on type 'never'.
      el.href = url;
    }
    if (isAnchorElement(el)) {
      // `el` is narrowed to `HTMLAnchorElement` type only inside
      // this if block and you're able to access `HTMLAnchorElement` specific
      // properties
      el.href = url;
    } else if (isImageElement(el) || isFrameElement(el)) {
      // `el` is narrowed to `HTMLImageElement | HTMLFrameElement` union type
      el.src = url;
    }
  }
  ```

User-defined type guards are a form of runtime checks, which means the variable is of expected type at the code execution moment. `typeof` operator is great for narrowing primitive types such as `number` or `string`. `instanceof` operator is possible to use with constructor functions (or classes). User-defined type guards are possible to use when the type should be narrowed to some user-defined `type` or `interface`, that cannot be narrowed with `typeof` or `instanceof`.

## Don't use the upper-case primitive types

Use the lower-case types for consistency

- `String` => `string`
- `Boolean` => `boolean`
- `Number` => `number`
- Avoid the `Function` type, as it provides little safety for the following reasons:
  - It provides no type safety when calling the value, which means it's easy to provide the wrong arguments.
  - It accepts class declarations, which will fail when called, as they are called without the new keyword.
- Avoid the `Object` and `object` (`{}`) types, as they mean "any non-nullish value".
  - This is a point of confusion for many developers, who think it means "any object type".
    [See this comment for more information](https://github.com/typescript-eslint/typescript-eslint/issues/2063#issuecomment-675156492).
  - The best way to prevent confusion is to specify what object is expected.
    - `{ [key: string]: number }` for key (string) value (number) pair gives more clarity than `{}` alone
- Avoid the `object` type, as it is currently hard to use due to not being able to assert that keys exist.
  - See [microsoft/TypeScript#21732](https://github.com/microsoft/TypeScript/issues/21732).

# Declarations

- Use module augmentation technique to augment already existing declarations, don't use `any`:
  ```ts
  // ✗ avoid
  (window as any).someVariable = 10;
  // ✓ good
  // The TypeScript compiler recursively reads all declarations files starting from the
  // folder root.
  // typings.d.ts
  declare interface Window {
    // Leave some comments here for other developers like
    // why this property is needed, its purpose, etc.
    someVariable: number;
  }
  window.someVariable = 10;
  ```
- Always install type declarations for third-party packages that don't have its own declarations, e.g:
  ```bash
  yarn add backbone
  yarn add -D @types/backbone
  ```
