Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/bitwarden/clients/llms.txt

Use this file to discover all available pages before exploring further.

This guide covers TypeScript configuration and coding patterns used across the Bitwarden client applications.

TypeScript Configuration

The project uses a centralized TypeScript configuration in tsconfig.base.json that is extended by individual packages.

Compiler Options

Type Checking

{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true
  }
}
Key settings:
  • strict: false - Strict mode is disabled at the base level
  • noImplicitAny: true - Must explicitly type variables (no implicit any)
  • Uses typescript-strict-plugin for gradual strict mode adoption per file

Module Configuration

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "ES2016",
    "module": "ES2020",
    "lib": ["es5", "es6", "es7", "dom", "ES2021", "ESNext.Disposable"]
  }
}
  • Target: ES2016 for broad compatibility
  • Module: ES2020 for modern module features
  • Lib: Includes ESNext.Disposable for resource management

Decorator Support

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "useDefineForClassFields": false
  }
}
Required for Angular dependency injection and decorators.

Path Mappings

The project uses extensive path mappings to enable clean imports across the monorepo:
// Instead of:
import { Something } from '../../../common/src/services/something';

// Use:
import { Something } from '@bitwarden/common/services/something';
Available path prefixes:
  • @bitwarden/common/* - Core shared logic
  • @bitwarden/angular/* - Angular-specific utilities
  • @bitwarden/auth/* - Authentication modules
  • @bitwarden/components - Component library
  • @bitwarden/vault - Vault-specific code
  • @bitwarden/platform - Platform abstractions
  • And many more (see tsconfig.base.json:20-74 for full list)

Build Configuration

{
  "compilerOptions": {
    "declaration": false,
    "sourceMap": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "allowJs": true
  }
}

TypeScript Patterns

Explicit Types

Required: Always specify types for function parameters and return values.
// Good
function getUser(id: string): Promise<User> {
  return userService.get(id);
}

// Bad - implicit any
function getUser(id) {
  return userService.get(id);
}

Avoid any

While @typescript-eslint/no-explicit-any is currently disabled, avoid using any types.
// Preferred
function processData(data: unknown): void {
  if (typeof data === 'string') {
    // TypeScript now knows data is a string
  }
}

// Avoid
function processData(data: any): void {
  // No type safety
}

Member Accessibility

Per ESLint rules (@typescript-eslint/explicit-member-accessibility), omit public keyword:
// Good
class UserService {
  private apiUrl: string;
  protected cache: Map<string, User>;
  
  getUser(id: string): User {  // No 'public' needed
    return this.cache.get(id);
  }
}

// Bad
class UserService {
  public getUser(id: string): User {  // Unnecessary 'public'
    return this.cache.get(id);
  }
}

Promises

Always await or handle promises (@typescript-eslint/no-floating-promises):
// Good
await userService.save(user);

// Good - intentionally not awaited
void userService.save(user);

// Bad - floating promise
userService.save(user);

Unused Variables

Function arguments named _ or unused are allowed (@typescript-eslint/no-unused-vars):
// Allowed
array.map((_, index) => index);

function callback(error: Error, data: Data) {
  // 'error' parameter unused but required by signature
  return data;
}

Gradual Strict Mode

The project uses typescript-strict-plugin to enable strict mode on a per-file basis:
// Add to the top of files ready for strict mode
// @ts-strict-enabled
This allows gradual migration to full strict mode without breaking the entire codebase.

Import Best Practices

Use Path Mappings

Always prefer @bitwarden/* imports over relative paths:
// Good
import { CryptoService } from '@bitwarden/common/platform/abstractions/crypto.service';

// Avoid
import { CryptoService } from '../../../platform/abstractions/crypto.service';

Alphabetize Imports

Imports are automatically organized by ESLint (import/order):
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';

import { CryptoService } from '@bitwarden/common/platform/abstractions/crypto.service';
import { I18nService } from '@bitwarden/common/platform/abstractions/i18n.service';

import { UserService } from 'src/app/services/user.service';
Order:
  1. Built-in/external packages (alphabetically)
  2. @bitwarden/* packages (alphabetically)
  3. src/ relative imports (alphabetically)
  4. Blank lines between groups

Type Safety Tools

Running Type Checks

npm run test:types
This runs type checking across the entire codebase using the test-types script.

ESLint Type-Aware Rules

Many ESLint rules require type information and use tsconfig.eslint.json:
{
  "languageOptions": {
    "parserOptions": {
      "project": ["./tsconfig.eslint.json"]
    }
  }
}
This enables advanced rules like:
  • @typescript-eslint/no-floating-promises
  • @typescript-eslint/no-misused-promises
  • Type-aware import resolution

Common Patterns

Ternary Expressions

Ternary expressions in statements are allowed (@typescript-eslint/no-unused-expressions):
// Allowed
condition ? doSomething() : doSomethingElse();

This Aliasing

Only self is allowed as an alias for this (@typescript-eslint/no-this-alias):
// Allowed
const self = this;
subscription.subscribe(() => {
  self.update();
});

// Not allowed
const that = this;

Next Steps