All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.l10n.javascript.rules.javascript.S6565.html Maven / Gradle / Ivy

There is a newer version: 10.17.0.28100
Show newest version

A fluent interface designates an object-oriented API relying on method chaining to improve code readability. In such interfaces, methods return the object this to allow the caller to chain multiple method invocations.

class RichText {
    constructor(private readonly text: string) {}
    bold(): RichText {
        // [...]
        return this;
    }
    italic(): RichText {
        // [...]
        return this;
    }
}

const richText = new RichText('Hello, World!');
// Chaining methods bold() and italic().
console.log(richText.bold().italic());

To better support fluent interfaces when used with a hierarchy of classes, TypeScript provides a special type this that refers dynamically to the type of the current class.

Methods returning this should thus use the corresponding special type this instead of the class name in their signatures.

Why is this an issue?

When a method return type is the declaring class name in a hierarchy of classes, it is impossible to chain methods defined in the superclass with methods defined in subclasses.

enum Color {
    RED, BLUE, GREEN
}

class Shape {
    // The return type is the class name.
    move(x: number, y: number): Shape {
        // [...]
        return this;
    }
}

class Polygon extends Shape {
    fill(color: Color): Polygon {
        // [...]
        return this;
    }
}

const polygon = new Polygon();
polygon.move(1.0, 2.0).fill(Color.RED);
//                     ^^^^
//                     Property 'fill' does not exist on type 'Shape'.

How to fix it

When a method declaration uses the special type this instead of the class name for its return type, TypeScript will use the type of the object this instead of the method declaring class and will accept to invoke methods defined in the object class:

enum Color {
    RED, BLUE, GREEN
}

class Shape {
    // The return type is now "this"
    move(x: number, y: number): this {
        // [...]
        return this;
    }
}

class Polygon extends Shape {
    fill(color: Color): this {
        // [...]
        return this;
    }
}

const polygon = new Polygon();
polygon.move(1.0, 2.0).fill(Color.RED); // No compilation error

Code examples

Noncompliant code example

class A {
  foo(): A { // Noncompliant
    return this;
  }
  bar = (): A => { // Noncompliant
    return this;
  };
}

Compliant solution

class A {
  foo(): this {
    return this;
  }
  bar = (): this => {
    return this;
  };
}

Resources

Documentation





© 2015 - 2024 Weber Informatics LLC | Privacy Policy