Require function parameters to be typed as
readonly
to prevent accidental mutation of inputs.
💭
This rule requires type information to run, which comes with performance tradeoffs.
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.
This rule allows you to enforce that function parameters resolve to readonly types. A type is considered readonly if:
string
, number
, boolean
, symbol
, or an enum),eslint.config.mjs
export default tseslint.config({
rules: {
"@typescript-eslint/prefer-readonly-parameter-types": "error"
}
});
.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/prefer-readonly-parameter-types": "error"
}
};
Try this rule in the playground ↗
Examplesfunction array1(arg: string[]) {}
function array2(arg: readonly string[][]) {}
function array3(arg: [string, number]) {}
function array4(arg: readonly [string[], number]) {}
function object1(arg: { prop: string }) {}
function object2(arg: { readonly prop: string; prop2: string }) {}
function object3(arg: { readonly prop: { prop2: string } }) {}
interface CustomArrayType extends ReadonlyArray<string> {
prop: string;
}
function custom1(arg: CustomArrayType) {}
interface CustomFunction {
(): void;
prop: string;
}
function custom2(arg: CustomFunction) {}
function union(arg: string[] | ReadonlyArray<number[]>) {}
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;
}
Open in Playground
function array1(arg: readonly string[]) {}
function array2(arg: readonly (readonly string[])[]) {}
function array3(arg: readonly [string, number]) {}
function array4(arg: readonly [readonly string[], number]) {}
function object1(arg: { readonly prop: string }) {}
function object2(arg: { readonly prop: string; readonly prop2: string }) {}
function object3(arg: { readonly prop: { readonly prop2: string } }) {}
interface CustomArrayType extends ReadonlyArray<string> {
readonly prop: string;
}
function custom1(arg: Readonly<CustomArrayType>) {}
interface CustomFunction {
(): void;
readonly prop: string;
}
function custom2(arg: CustomFunction) {}
function union(arg: readonly string[] | ReadonlyArray<number>) {}
function primitive1(arg: string) {}
function primitive2(arg: number) {}
function primitive3(arg: boolean) {}
function primitive4(arg: unknown) {}
function primitive5(arg: null) {}
function primitive6(arg: undefined) {}
function primitive7(arg: any) {}
function primitive8(arg: never) {}
function primitive9(arg: string | number | undefined) {}
function fnSig(arg: () => void) {}
enum Foo {
a,
b,
}
function enumArg(arg: Foo) {}
function symb1(arg: symbol) {}
const customSymbol = Symbol('a');
function symb2(arg: typeof customSymbol) {}
interface Foo {
(arg: readonly string[]): void;
}
interface Foo {
new (arg: readonly string[]): void;
}
const x = { foo(arg: readonly string[]): void {} };
function foo(arg: readonly string[]);
type Foo = (arg: readonly string[]) => void;
interface Foo {
foo(arg: readonly string[]): void;
}
Open in Playground Options
This rule accepts the following options:
type Options = [
{
allow?: (
| {
from: 'file';
name: string | string[];
path?: string;
}
| {
from: 'lib';
name: string | string[];
}
| {
from: 'package';
name: string | string[];
package: string;
}
| string
)[];
checkParameterProperties?: boolean;
ignoreInferredTypes?: boolean;
treatMethodsAsReadonly?: boolean;
},
];
const defaultOptions: Options = [
{
allow: [],
checkParameterProperties: true,
ignoreInferredTypes: false,
treatMethodsAsReadonly: false,
},
];
allow
An array of type specifiers to ignore. Default: []
.
Some complex types cannot easily be made readonly, for example the HTMLElement
type or the JQueryStatic
type from @types/jquery
. This option allows you to globally disable reporting of such types.
This option takes the shared TypeOrValueSpecifier
format.
Examples of code for this rule with:
{
"allow": [
{ "from": "file", "name": "Foo" },
{ "from": "lib", "name": "HTMLElement" },
{ "from": "package", "name": "Bar", "package": "bar-lib" }
]
}
interface ThisIsMutable {
prop: string;
}
interface Wrapper {
sub: ThisIsMutable;
}
interface WrapperWithOther {
readonly sub: Foo;
otherProp: string;
}
function fn1(arg: ThisIsMutable) {}
function fn2(arg: Wrapper) {}
function fn3(arg: WrapperWithOther) {}
Open in Playground
import { Foo } from 'some-lib';
import { Bar } from 'incorrect-lib';
interface HTMLElement {
prop: string;
}
function fn1(arg: Foo) {}
function fn2(arg: HTMLElement) {}
function fn3(arg: Bar) {}
Open in Playground
interface Foo {
prop: string;
}
interface Wrapper {
readonly sub: Foo;
readonly otherProp: string;
}
function fn1(arg: Foo) {}
function fn2(arg: Wrapper) {}
Open in Playground
import { Bar } from 'bar-lib';
interface Foo {
prop: string;
}
function fn1(arg: Foo) {}
function fn2(arg: HTMLElement) {}
function fn3(arg: Bar) {}
Open in Playground checkParameterProperties
Whether to check class parameter properties. Default: true
.
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}
:
Examples of correct code for this rule with {checkParameterProperties: false}
:
class Foo {
constructor(
private paramProp1: string[],
private paramProp2: readonly string[],
) {}
}
Open in Playground ignoreInferredTypes
Whether to ignore parameters which don't explicitly specify a type. Default: false
.
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';
acceptsCallback((options: CallbackOptions) => {});
Open in Playground external-dependency.d.ts
export interface CallbackOptions {
prop: string;
}
type Callback = (options: CallbackOptions) => void;
type AcceptsCallback = (callback: Callback) => void;
export const acceptsCallback: AcceptsCallback;
import { acceptsCallback } from 'external-dependency';
acceptsCallback(options => {});
Open in Playground external-dependency.d.ts
export interface CallbackOptions {
prop: string;
}
type Callback = (options: CallbackOptions) => void;
type AcceptsCallback = (callback: Callback) => void;
export const acceptsCallback: AcceptsCallback;
treatMethodsAsReadonly
Whether to treat all mutable methods as though they are readonly. Default: false
.
This may be desirable when you are never reassigning methods.
Examples of code for this rule with {treatMethodsAsReadonly: false}
:
type MyType = {
readonly prop: string;
method(): string;
};
function foo(arg: MyType) {}
Open in Playground
type MyType = Readonly<{
prop: string;
method(): string;
}>;
function foo(arg: MyType) {}
type MyOtherType = {
readonly prop: string;
readonly method: () => string;
};
function bar(arg: MyOtherType) {}
Open in Playground
Examples of correct code for this rule with {treatMethodsAsReadonly: true}
:
type MyType = {
readonly prop: string;
method(): string;
};
function foo(arg: MyType) {}
Open in Playground When Not To Use It
If your project does not attempt to enforce strong immutability guarantees of parameters, you can avoid this rule.
This rule is very strict on what it considers mutable. Many types that describe themselves as readonly are considered mutable because they have mutable properties such as arrays or tuples. To work around these limitations, you might need to use the rule's options. In particular, the allow
option can explicitly mark a type as readonly.
Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting.
See Troubleshooting > Linting with Type Information > Performance if you experience performance degradations after enabling type checked rules.
ResourcesRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4