Skip to main content

prefer-readonly-parameter-types

Requires that function parameters are typed as readonly to prevent accidental mutation of inputs.

Mutating function arguments can lead to confusing, hard to debug behavior. Whilst it's easy to implicitly remember to not modify function arguments, explicitly typing arguments as readonly provides clear contract to consumers. This contract makes it easier for a consumer to reason about if a function has side-effects.

Rule Details

This rule allows you to enforce that function parameters resolve to readonly types. A type is considered readonly if:

  • it is a primitive type (string, number, boolean, symbol, or an enum),
  • it is a function signature type,
  • it is a readonly array type whose element type is considered readonly.
  • it is a readonly tuple type whose elements are all considered readonly.
  • it is an object type whose properties are all marked as readonly, and whose values are all considered readonly.

Examples of code for this rule:

function array1(arg: string[]) {} // array is not readonly
function array2(arg: readonly string[][]) {} // array element is not readonly
function array3(arg: [string, number]) {} // tuple is not readonly
function array4(arg: readonly [string[], number]) {} // tuple element is not readonly
// the above examples work the same if you use ReadonlyArray<T> instead

function object1(arg: { prop: string }) {} // property is not readonly
function object2(arg: { readonly prop: string; prop2: string }) {} // not all properties are readonly
function object3(arg: { readonly prop: { prop2: string } }) {} // nested property is not readonly
// the above examples work the same if you use Readonly<T> instead

interface CustomArrayType extends ReadonlyArray<string> {
prop: string; // note: this property is mutable
}
function custom1(arg: CustomArrayType) {}

interface CustomFunction {
(): void;
prop: string; // note: this property is mutable
}
function custom2(arg: CustomFunction) {}

function union(arg: string[] | ReadonlyArray<number[]>) {} // not all types are readonly

// rule also checks function types
interface Foo {
(arg: string[]): void;
}
interface Foo {
new (arg: string[]): void;
}
const x = { foo(arg: string[]): void; };
function foo(arg: string[]);
type Foo = (arg: string[]) => void;
interface Foo {
foo(arg: string[]): void;
}

Options

interface Options {
checkParameterProperties?: boolean;
ignoreInferredTypes?: boolean;
}

const defaultOptions: Options = {
checkParameterProperties: true,
ignoreInferredTypes: false,
treatMethodsAsReadonly: false,
};

checkParameterProperties

This option allows you to enable or disable the checking of parameter properties. Because parameter properties create properties on the class, it may be undesirable to force them to be readonly.

Examples of code for this rule with {checkParameterProperties: true}:

class Foo {
constructor(private paramProp: string[]) {}
}

Examples of correct code for this rule with {checkParameterProperties: false}:

class Foo {
constructor(
private paramProp1: string[],
private paramProp2: readonly string[],
) {}
}

ignoreInferredTypes

This option allows you to ignore parameters which don't explicitly specify a type. This may be desirable in cases where an external dependency specifies a callback with mutable parameters, and manually annotating the callback's parameters is undesirable.

Examples of code for this rule with {ignoreInferredTypes: true}:

import { acceptsCallback, CallbackOptions } from 'external-dependency';

acceceptsCallback((options: CallbackOptions) => {});
external-dependency.d.ts
export interface CallbackOptions {
prop: string;
}
type Callback = (options: CallbackOptions) => void;
type AcceptsCallback = (callback: Callback) => void;

export const acceptsCallback: AcceptsCallback;

treatMethodsAsReadonly

This option allows you to treat all mutable methods as though they were readonly. This may be desirable in when you are never reassigning methods.

Examples of code for this rule with {treatMethodsAsReadonly: false}:

type MyType = {
readonly prop: string;
method(): string; // note: this method is mutable
};
function foo(arg: MyType) {}

Examples of correct code for this rule with {treatMethodsAsReadonly: true}:

type MyType = {
readonly prop: string;
method(): string; // note: this method is mutable
};
function foo(arg: MyType) {}

Attributes

  • ✅ Recommended
  • 🔧 Fixable
  • 💭 Requires type information