Engineering/Coding Standards/TypeScript/TypeScript Maintainability/

TypeScript Maintainability Standards · TS-02

Clean, scalable codebases are crucial for long-term project success. Best practices are outlined within this document for guiding engineers to write maintainable TypeScript.

Methods do not exceed 10 statements · TS-02.1 · MUST

A TypeScript reflection of CS-01.1

Methods that require more than 10 statements are doing too much, engineers must make conscious, critical analysis of their work and provide methods with clear names.

Do not duplicate code · TS-02.2 · MUST

If the same statement, or statement group, appears multiple times in the codebase. Then, the responsibility of this logic should belong to one abstraction which is used in both places.

This rule enforces the DRY principle

Nested control statements do not exceed a depth of 2 · TS-02.3 · MUST

Methods which contain control statements (such as if, while, for) must only have up to 2 of such statements nested before abstracting the nested control statements into private methods.

Excessive nesting results in unmaintainable code which takes time to understand. Engineers must abstract each stage of the nested statements into a understandable methods.

Do not allow methods with more than 4 parameters · TS-02.4 · MUST

A TypeScript reflection of CS-01.21

Reduce method complexity by ensuring methods do not have more than 4 parameters. Use objects or data structures to encapsulate multiple parameters if necessary.

Do not use magic numbers or strings · TS-02.5 · MUST

Magic numbers and strings present maintainability issues and must be avoided at all times.

Use Enums over fixed sets of constants · TS-02.6 · MUST

When a fixed set of constants is used for logic, these should be grouped into an Enum. This aides readibilty by giving names and groupings to magic numbers and strings.

Allow gaps between numeric values for enums · TS-02.7 · MUST

A TypeScript reflection of CS-01.27

Allow future extensions or specific business requirements by leaving gaps between the numeric values of an enum, e.g. [0, 100, 200].

Don't comment out code · TS-02.8 · MUST

A TypeScript reflection of CS-01.26

To maintain cleanliness, any code that the compiler cannot reach should never be checked-in.

Target specific versions or version ranges in package.json · TS-02.9 · MUST

Never use ”*” or ”^” for the target version of an imported package. This kind of usage can result in unexpected behaviour or the unintentional introduction of breaking changes.

Implement error logging for observability of problems · TS-02.10 · MUST

Integrate a logging tool to track and diagnose runtime errors in development and production. This can be achieved with an error handling middleware.

Error logging tool such as Sentry or Winston can be implemented to capture errors on the front end.

Limit the contents of a source code file to one type · TS-02.11 · SHOULD

A TypeScript reflection of CS-01.6

Enable strictNullChecks for Type safety · TS-02.12 · SHOULD

Type null safety should be enforced on TS projects, making full use of TypeScript’s benefits that reduce runtime errors and aide readibility. Engineers should be made to explciity state if a value might be null or undefined.

Optimise imports · TS-02.13 · SHOULD

Optimising imports is important for the scalability of an application. As applications grow and file paths become longer as a result, it’s important that we keep these maintainable and readable.

Use relative imports · TS-02.14 · SHOULD

Dependency management and module portability should be optimised through the use of relative paths.

Relative import example (✅)

import { MyComponent } from './components/MyComponent';
import { Utils } from '../utils/Utils';

Absolute import example (❌)

import { MyComponent } from 'project-name/src/components/MyComponent';
import { Utils } from 'project-name/src/utils/Utils';

Configure aliases for improved readability · TS-02.15 · SHOULD

Aliases can be configured in tsconfig.json or in webpack to optimise imports into groups.

tsconfig.json alias example (✅)

  "compilerOptions": {
    "paths": {
      "@components/*": ["src/components/*"],
    }
  }

Usage

import { MyComponent } from '@components/MyComponent';