Home

Awesome

eslint-config-clean-typescript

NPM Version

Enforce classic JavaScript features in TypeScript codebase by banning excessive keywords

Though TypeScript has brought us type-safety for web development, many developers agree on that it has too many duplicated keywords and ways of writing code to achieve the same thing.

Not only that, TypeScript is not a standard web language. It might be hard to refactor the code once alternatives such as the type annotation proposal for JavaScript arise, if the codebase contains too much TypeScript-specific syntax.

This package is an opinionated ESLint configuration. The basic principle is not to declare things that don't exist in JavaScript. By doing so, TypeScript can be more coherent with JavaScript, while assisting only in areas that are related to type safety.

Table of Contents

Installation

This guide assumes that you're inside your Node project directory with package.json.

Additionally, this configuration relies on eslint and typescript-eslint. You should have .eslintrc.js or similar in your project folder, by following the exact steps introduced in the eslint docs and typescript-eslint docs.

Once the prerequisites are ready, install this configuration.

npm install --save-dev eslint-config-clean-typescript

Then, add this configuration to .eslintrc.js or similar.

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/stylistic",
    "eslint-config-clean-typescript" // ADD THIS LINE
  ]
}

Rules

Class Based Types

Whether to use type, interface, or class to represent a typed structure has been a long-standing controversy in the TypeScript community.

This is related to the historical path of TypeScript, where the interface keyword was introduced in 2012, when JavaScript class keyword was not a thing yet. The JavaScript class keyword was introduced later in 2015.

This configuration makes your codebase use only class for types, to adhere to classic JavaScript way of doing object-oriented programming.

// Produces warning
enum MyEnum {
  A = "west",
  B = "east",
}

// Produces warning
interface MyInterface {
  a: number;
  b: string;
}
// OK
class MyEnum {
  static A = "west";
  static B = "east";
}

// OK
class MyInterface {
  a: number;
  b: string;
}

Consider using optional types such as number | undefined for fields that can be empty or extended. This is equivalent to TypeScript's Omit or Pick.

// Recommended
class MyClass {
  a?: number; // number | undefined
  b?: string; // string | undefined
}

No Type Aliases

Type statements are ghost declarations that don't actually exist in JavaScript.

// Produces warning
type ShapeType = { a: boolean; b: boolean };

// Produces warning
type AliasType = Array<string>;

// Not recommended
function myFunction(array: AliasType) {
  console.log(array);
}
// Recommended
function myFunction(array: Array<string>) {
  console.log(array);
}

No Namespaces

ES6 modules should be used instead of namespaces. TypeScript was heavily influced by C++ and C#, and the namespace keyword doesn't align well with JavaScript practices. This rule is also included in typescript-eslint's recommended configuration.

// Produces warning
namespace MyNamespace {}

Array Type Annotations

Preferring Array<T> over T[] is for ensuring alignment with high-level language paradigm, particularly in the context of JavaScript development.

Although T[] may be more familiar to developers from lower-level languages like C, C++, and Rust, where arrays represent contiguous memory spaces, it does not really make sense for high-level languages like JavaScript.

In contrast, Array<T> provides a more explicit and descriptive representation of the Array type in JavaScript. This clarity is particularly beneficial for developers collaborating on projects, as it reduces ambiguity and aids in understanding the constructor and prototype of an array.

// Produces warning
const array: number[] = [1, 2, 3];
// OK
const array: Array<number> = [1, 2, 3];