Skip to content

Rule proposal: Ban implicit conversion of Readonly<T> to T #11833

@bkietz

Description

@bkietz

Before You File a Proposal Please Confirm You Have Done The Following...

My proposal is suitable for this project

  • My proposal specifically checks TypeScript syntax, or it proposes a check that requires type information to be accurate.
  • My proposal is not a "formatting rule"; meaning it does not just enforce how code is formatted (whitespace, brace placement, etc).
  • I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).

Description

TypeScript silently allows an expression of type Readonly<T> to be passed as an argument of type T. This results in a loss of the readonly type information in the scope of the called function and potential unintended mutation.

Fail Cases

// Declaring a variable Readonly should guard against future modification, even at a lower scope
const dangerous: Readonly<number[]> = getDangerousToModify();

// Fails since pushOne() requires a mutable argument
pushOne(dangerous);
function pushOne(a: number[]): void { a.push(1); };

Pass Cases

// Making a copy results in a mutable array, so the rule accepts this
const dangerousCopy = [...dangerous];
pushOne(dangerousCopy);

// If mutation is really intended, type assertion will also be accepted
pushOne(dangerous as number[]);

Additional Info

In combination with explicit this parameters, this also enables methods to declare they are guaranteed not to modify the object:

class Vec3 {
  constructor(public x: number, public y: number, public z: number) {}

  norm(this: Readonly<this>): number {
    return Math.hypot(this.x, this.y, this.z);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancement: new plugin ruleNew rule request for eslint-pluginpackage: eslint-pluginIssues related to @typescript-eslint/eslint-plugintriageWaiting for team members to take a look

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions